pax_global_header00006660000000000000000000000064136353301710014514gustar00rootroot0000000000000052 comment=f1e279a30faaa77be51085d69360da8182ca57e3 intel-graphics-compiler-igc-1.0.3627/000077500000000000000000000000001363533017100172355ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/.travis.yml000066400000000000000000000121301363533017100213430ustar00rootroot00000000000000language: cpp #llvm 8 v8: &v8 - llvm-8-tools - llvm-8-dev - libclang-8-dev - clang-8 - clang-tools-8 #SPIRV for llvm8 v8install: &v8install - export TARBALL1=SPIRV-LLVM-Translator-v8.0.1-2-linux-${BUILD_TYPE}.zip - wget https://github.com/KhronosGroup/SPIRV-LLVM-Translator/releases/download/v8.0.1-2/${TARBALL1} -O /tmp/${TARBALL1} - unzip /tmp/${TARBALL1} -d spirv-llvm-translator #llvm 9 v9: &v9 - llvm-9-tools - llvm-9-dev - libclang-9-dev - clang-9 - clang-tools-9 #SPIRV for llvm9 v9install: &v9install - export TARBALL2=SPIRV-LLVM-Translator-v9.0.0-1-linux-${BUILD_TYPE}.zip - wget https://github.com/KhronosGroup/SPIRV-LLVM-Translator/releases/download/v9.0.0-1/${TARBALL2} -O /tmp/${TARBALL2} - unzip /tmp/${TARBALL2} -d spirv-llvm-translator matrix: include: - os: linux dist: xenial # Ubuntu 16.04 w/ llvm8 env: LLVM_VER=8 BUILD_TYPE=Release COMPILER=gcc before_install: - git clone -b ocl-open-80 https://github.com/intel/opencl-clang opencl-clang addons: apt: sources: - sourceline: 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: *v8 install: *v8install - os: linux dist: bionic # Ubuntu 18.04 w/ llvm8 env: LLVM_VER=8 BUILD_TYPE=Release COMPILER=gcc before_install: - git clone -b ocl-open-80 https://github.com/intel/opencl-clang opencl-clang addons: apt: sources: - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: *v8 install: *v8install - os: linux dist: xenial # Ubuntu 16.04 w/ llvm9 env: LLVM_VER=9 BUILD_TYPE=Release COMPILER=gcc before_install: - git clone -b ocl-open-90 https://github.com/intel/opencl-clang opencl-clang addons: apt: sources: - sourceline: 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: *v9 install: *v9install - os: linux dist: bionic # Ubuntu 18.04 w/ llvm9 env: LLVM_VER=9 BUILD_TYPE=Release COMPILER=gcc before_install: - git clone -b ocl-open-90 https://github.com/intel/opencl-clang opencl-clang addons: apt: sources: - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: *v9 install: *v9install - os: linux dist: xenial # Ubuntu 16.04 w/ llvm8 env: LLVM_VER=8 BUILD_TYPE=Release COMPILER=clang before_install: - git clone -b ocl-open-80 https://github.com/intel/opencl-clang opencl-clang addons: apt: sources: - sourceline: 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: *v8 install: *v8install - os: linux dist: bionic # Ubuntu 18.04 w/ llvm8 env: LLVM_VER=8 BUILD_TYPE=Release COMPILER=clang before_install: - git clone -b ocl-open-80 https://github.com/intel/opencl-clang opencl-clang addons: apt: sources: - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: *v8 install: *v8install - os: linux dist: xenial # Ubuntu 16.04 w/ llvm9 env: LLVM_VER=9 BUILD_TYPE=Release COMPILER=clang before_install: - git clone -b ocl-open-90 https://github.com/intel/opencl-clang opencl-clang addons: apt: sources: - sourceline: 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: *v9 install: *v9install - os: linux dist: bionic # Ubuntu 18.04 w/ llvm9 env: LLVM_VER=9 BUILD_TYPE=Release COMPILER=clang before_install: - git clone -b ocl-open-90 https://github.com/intel/opencl-clang opencl-clang addons: apt: sources: - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: *v9 install: *v9install git: depth: 1 branches: only: - master script: - if [ "${LLVM_VER}" == "9" ]; then sudo touch /usr/lib/llvm-9/bin/lit-cpuid; fi #Cmake fix - mkdir opencl-clang/build && cd opencl-clang/build - cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DLLVM_NO_DEAD_STRIP=ON -DLLVMSPIRV_INCLUDED_IN_LLVM=OFF -DSPIRV_TRANSLATOR_DIR=../spirv-llvm-translator .. - sudo make install - cd ../.. - mkdir build && cd build - cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_FIND_DEBUG_MODE=ON -DIGC_PREFERRED_LLVM_VERSION=${LLVM_VER} -DCCLANG_FROM_SYSTEM=TRUE ../IGC - make -j`nproc` intel-graphics-compiler-igc-1.0.3627/3d/000077500000000000000000000000001363533017100175435ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/3d/common/000077500000000000000000000000001363533017100210335ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/000077500000000000000000000000001363533017100223655ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Alloc.h000066400000000000000000000062411363533017100235730ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Debug.h" #ifdef __cplusplus namespace iSTD { /*****************************************************************************\ Function: SafeDelete Description: Safe "delete ptr;" Input: Type &ptr - pointer to memory to delete Output: Type &ptr \*****************************************************************************/ template inline void SafeDelete( Type &ptr ) { if( ptr ) { #if defined( _DEBUG ) && !defined( NO_EXCEPTION_HANDLING ) #if defined( __GNUC__ ) try { delete ptr; } catch (...) { ASSERT(0); } #else // defined( __GNUC__ ) __try { delete ptr; } __except (1) { ASSERT(0); } #endif // defined( __GNUC__ ) #else // defined( _DEBUG ) && !defined( NO_EXCEPTION_HANDLING ) delete ptr; #endif // defined( _DEBUG ) && !defined( NO_EXCEPTION_HANDLING ) ptr = 0; } }; /*****************************************************************************\ Function: SafeDeleteArray Description: Safe "delete[] ptr;" Input: Type &ptr - pointer to memory to delete Output: Type &ptr \*****************************************************************************/ template inline void SafeDeleteArray( Type &ptr ) { if( ptr ) { #if defined( _DEBUG ) && !defined( NO_EXCEPTION_HANDLING ) #if defined( __GNUC__ ) try { delete[] ptr; } catch (int e) { ASSERT(0); } #else // defined( __GNUC__ ) __try { delete[] ptr; } __except (1) { ASSERT(0); } #endif // defined( __GNUC__ ) #else // defined( _DEBUG ) && !defined( NO_EXCEPTION_HANDLING ) delete[] ptr; #endif // defined( _DEBUG ) && !defined( NO_EXCEPTION_HANDLING ) ptr = 0; } }; } // iSTD #endif // __cplusplus intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Array.h000066400000000000000000001031311363533017100236130ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #include "Queue.h" #include "MemCopy.h" namespace iSTD { /*****************************************************************************\ Struct: IsArrayTypeSupported \*****************************************************************************/ template struct IsArrayTypeSupported { enum { value = false }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; #ifndef __LP64__ // u/long on linux64 platform is 64-bit type and collides with U/INT64 template<> struct IsArrayTypeSupported { enum { value = true }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; #endif template<> struct IsArrayTypeSupported { enum { value = true }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; template<> struct IsArrayTypeSupported { enum { value = true }; }; template struct IsArrayTypeSupported { enum { value = true }; }; /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define ArrayTemplateList class Type, class CAllocatorType #define CStaticArrayType CStaticArray #define CDynamicArrayType CDynamicArray #define CArrayType CArray /*****************************************************************************\ Class: CStaticArray Description: Implements a statically-sized array \*****************************************************************************/ template class CStaticArray : public CObject { public: CStaticArray( const DWORD maxSize ); virtual ~CStaticArray( void ); Type GetElement( const DWORD index ) const; Type GetElementUnsafe( const DWORD index ) const; bool SetElement( const DWORD index, const Type& element ); void SetElementUnsafe( const DWORD index, const Type& element ); DWORD GetSize( void ) const; void Clear( void ); void DebugPrint( void ) const; CStaticArrayType& operator= ( const CStaticArrayType &array ); C_ASSERT( IsArrayTypeSupported::value == true ); protected: Type* m_pArrayBuffer; DWORD m_ActualSize; }; /*****************************************************************************\ Function: CStaticArray Constructor Description: Initializes the array Input: const DWORD maxSize - maximum size of the array, in elements Output: none \*****************************************************************************/ template CStaticArrayType::CStaticArray( const DWORD maxSize ) : CObject() { m_pArrayBuffer = (Type*)CAllocatorType::AlignedAllocate( maxSize * sizeof(Type), sizeof(Type) ); if( m_pArrayBuffer ) { SafeMemSet( m_pArrayBuffer, 0, (maxSize * sizeof(Type)) ); m_ActualSize = maxSize; } else { m_ActualSize = 0; } } /*****************************************************************************\ Function: CStaticArray Destructor Description: Frees all internal dynamic memory Input: none Output: none \*****************************************************************************/ template CStaticArrayType::~CStaticArray( void ) { if( m_pArrayBuffer ) { CAllocatorType::AlignedDeallocate( m_pArrayBuffer ); m_pArrayBuffer = NULL; } m_ActualSize = 0; } /*****************************************************************************\ Function: CStaticArray::GetElement Description: Returns the element at the index in the array Input: const DWORD index - index of element to reference Output: Type - value of element in array \*****************************************************************************/ template Type CStaticArrayType::GetElement( const DWORD index ) const { Type element; if( m_pArrayBuffer && ( index < m_ActualSize ) ) { element = m_pArrayBuffer[ index ]; } else { ASSERT(0); SafeMemSet( &element, 0, sizeof(Type) ); } return element; } /*****************************************************************************\ Function: CStaticArray::GetElementUnsafe Description: Returns the element at the index in the array Note that function does not check if index is in range! Input: const DWORD index - index of element to reference Output: Type - value of element in array \*****************************************************************************/ template Type CStaticArrayType::GetElementUnsafe( const DWORD index ) const { ASSERT( m_pArrayBuffer && ( index < m_ActualSize ) ); return m_pArrayBuffer[ index ]; } /*****************************************************************************\ Function: CStaticArray::SetElement Description: Sets the element at the index in the array to the given element Input: const DWORD index - index of element to reference const Type& element - value of element to set Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CStaticArrayType::SetElement( const DWORD index, const Type& element ) { bool success = false; if( m_pArrayBuffer && ( index < m_ActualSize ) ) { m_pArrayBuffer[ index ] = element; success = true; } ASSERT( success ); return success; } /*****************************************************************************\ Function: CStaticArray::SetElementUnsafe Description: Sets the element at the index in the array to the given element Note that function does not check if index is in range! Input: const DWORD index - index of element to reference const Type& element - value of element to set Output: None \*****************************************************************************/ template void CStaticArrayType::SetElementUnsafe( const DWORD index, const Type& element ) { ASSERT( m_pArrayBuffer && ( index < m_ActualSize ) ); m_pArrayBuffer[ index ] = element; } /*****************************************************************************\ Function: CStaticArray::GetSize Description: Returns the current number of elements in the array Input: void Output: DWORD - size of the array in elements \*****************************************************************************/ template DWORD CStaticArrayType::GetSize( void ) const { return m_ActualSize; } /*****************************************************************************\ Function: CStaticArray::Clear Description: Clears the array Input: none Output: none \*****************************************************************************/ template void CStaticArrayType::Clear( void ) { SafeMemSet( m_pArrayBuffer, 0, m_ActualSize * sizeof( Type ) ); } /*****************************************************************************\ Function: CStaticArray::DebugPrint Description: Prints the array to std output for debug only Input: void Output: void \*****************************************************************************/ template void CStaticArrayType::DebugPrint( void ) const { #ifdef _DEBUG DPF( GFXDBG_STDLIB, "%s\n", __FUNCTION__ ); DPF( GFXDBG_STDLIB, "\tAddress = %p\n", this ); if( m_pArrayBuffer ) { for( DWORD i = 0; i < GetSize(); i++ ) { Type element = GetElement(i); DPF( GFXDBG_STDLIB, "\t\tElement[%u] = 0x%08x\n", i, *(DWORD*)&element ); } } #endif } /*****************************************************************************\ Function: CStaticArray::operator= Description: Equal operator to copy an array Input: const CStaticArrayType& array - array to copy Output: *this \*****************************************************************************/ template CStaticArrayType& CStaticArrayType::operator= ( const CStaticArrayType &array ) { if( m_pArrayBuffer && array.m_pArrayBuffer ) { const DWORD copySize = Min( m_ActualSize, array.m_ActualSize ); MemCopy( m_pArrayBuffer, array.m_pArrayBuffer, copySize * sizeof( Type ) ); } return *this; } /*****************************************************************************\ Class: CDynamicArray Description: Implements a dynamically-sized array \*****************************************************************************/ template class CDynamicArray : public CObject { public: CDynamicArray( const DWORD initSize ); CDynamicArray( const DWORD initSize, const DWORD actualSize ); virtual ~CDynamicArray( void ); Type GetElement( const DWORD index ) const; bool SetElement( const DWORD index, const Type& element ); bool Insert( const DWORD index, const Type& element ); Type GetElementUnsafe( const DWORD index ) const; const Type& GetElementReference( const DWORD index) const; //when the index request in GetELementReference does not exist a //reference to m_elementNoExist is returned instead. //why is it not const? because that would force it to be an l-value in the //constructor but because it is a template type there is no universal value. Type m_elementNoExist; DWORD GetSize( void ) const; bool Resize( const DWORD size ); bool Shrink( const DWORD size ); void PreAllocate( const DWORD size ); void Delete( void ); void Clear( void ); void DebugPrint( void ) const; CDynamicArrayType& operator= ( const CDynamicArrayType &array ); C_ASSERT( IsArrayTypeSupported::value == true ); protected: virtual void CreateArray( const DWORD size ); void DeleteArray( void ); DWORD GetMaxSize( void ) const; bool IsValidIndex( const DWORD index ) const; Type* m_pArrayBuffer; DWORD m_UsedSize; DWORD m_ActualSize; DECL_DEBUG_MUTEX( m_InstanceNotThreadSafe ) }; /*****************************************************************************\ Function: CDynamicArray Constructor Description: Initializes the array Input: const DWORD initSize - initial size of the array, in elements Output: none \*****************************************************************************/ template CDynamicArrayType::CDynamicArray( const DWORD initSize ) : CObject() { m_pArrayBuffer = NULL; m_UsedSize = 0; m_ActualSize = 0; //can't use the zero initializer, {0}, on template types memset((void*)&m_elementNoExist, 0, sizeof(Type)); CreateArray( initSize ); INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CDynamicArray Destructor Description: Frees all internal dynamic memory Input: none Output: none \*****************************************************************************/ template CDynamicArrayType::~CDynamicArray( void ) { Delete(); DELETE_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CDynamicArray::GetElement Description: Returns the element at the index in the array Input: const DWORD index - index of element to reference Output: Type - value of element in array \*****************************************************************************/ template Type CDynamicArrayType::GetElement( const DWORD index ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); Type element; if( m_pArrayBuffer && IsValidIndex( index ) ) { element = m_pArrayBuffer[ index ]; } else { SafeMemSet( &element, 0, sizeof(Type) ); } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return element; } /*****************************************************************************\ Function: CDynamicArray::GetElementUnsafe Description: Returns the element at the index in the array Note that function does not check if index is in range! Input: const DWORD index - index of element to reference Output: Type - value of element in array \*****************************************************************************/ template Type CDynamicArrayType::GetElementUnsafe( const DWORD index ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); ASSERT( m_pArrayBuffer && IsValidIndex( index ) ); Type element = m_pArrayBuffer[ index ]; RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return element; } /*****************************************************************************\ Function: CDynamicArray::GetElementReference Description: Returns the a const reference to the element at the index in the array. Do not attempt to retain pointers to the reference returned as it will be invalid after a resize operation which can happen automatically. Input: const DWORD index - index of element to reference Output: const Type* - reference to the element in the array. returns NULL if element not found. \*****************************************************************************/ template const Type& CDynamicArrayType::GetElementReference( const DWORD index ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); if( m_pArrayBuffer && IsValidIndex( index ) ) { return m_pArrayBuffer[ index ]; } else { //returning the zeroed out structure is not the greatest, but the best //that can be done in this situation. when in debug builds the assert //will help point out that something bad is going on. ASSERT(m_pArrayBuffer && IsValidIndex( index )); return m_elementNoExist; } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CDynamicArray::SetElement Description: Sets the element at the index in the array to the given element Input: const DWORD index - index of element to reference const Type& element - value of element to set Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CDynamicArrayType::SetElement( const DWORD index, const Type& element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); bool success = false; // If the index is larger than the size of the array then grow the array if( !IsValidIndex( index ) ) { CreateArray( index + 1 ); } if( m_pArrayBuffer && IsValidIndex( index ) ) { m_pArrayBuffer[ index ] = element; success = true; } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); ASSERT( success ); return success; } /*****************************************************************************\ Function: CDynamicArray::Insert Description: Sets the element at the index in the array to the given element and shifts successors. Input: const DWORD index - index at which the element should be inserted const Type& element - value of element to insert Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CDynamicArrayType::Insert( const DWORD index, const Type& element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); const DWORD oldSize = GetSize(); // Grow the array. if( index < oldSize ) { CreateArray( oldSize + 1 ); SafeMemMove( m_pArrayBuffer + index + 1, m_pArrayBuffer + index, ( oldSize - index )*sizeof( Type ) ); } else { CreateArray( index + 1 ); } bool success = SetElement( index, element ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); ASSERT( success ); return success; } /*****************************************************************************\ Function: CDynamicArray::GetSize Description: Returns the current number of elements in the array Input: void Output: DWORD - size of the array in elements \*****************************************************************************/ template DWORD CDynamicArrayType::GetSize( void ) const { const DWORD size = m_UsedSize; return size; } /*****************************************************************************\ Function: CDynamicArray::Resize Description: Resize the array Input: const DWORD size - new size for the array Output: bool \*****************************************************************************/ template bool CDynamicArrayType::Resize( const DWORD size ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); bool success = true; const DWORD allocSize = size * sizeof( Type ); // TODO: add Reallocate function to CAllocator Type* pArrayBuffer = (Type*)CAllocatorType::Allocate( allocSize ); if( pArrayBuffer ) { SafeMemSet( pArrayBuffer, 0, allocSize ); if( m_pArrayBuffer ) { // copy the old array to the new array const DWORD copySize = Min( size, m_ActualSize ); MemCopy( pArrayBuffer, m_pArrayBuffer, copySize * sizeof( Type ) ); DeleteArray(); } m_pArrayBuffer = pArrayBuffer; m_ActualSize = size; m_UsedSize = size; } else { success = false; } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CDynamicArray::Shrink Description: Shrink the array Input: const DWORD size - new size for the array Output: bool \*****************************************************************************/ template bool CDynamicArrayType::Shrink( const DWORD size ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); bool success = false; if( size < m_UsedSize ) { success = true; m_UsedSize = size; } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CDynamicArray::Delete Description: Deletes the internal data Input: void Output: void \*****************************************************************************/ template void CDynamicArrayType::Delete( void ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); DeleteArray(); m_UsedSize = 0; RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CDynamicArray::Clear Description: Zeros the internal data Input: void Output: void \*****************************************************************************/ template void CDynamicArrayType::Clear( void ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); SafeMemSet( m_pArrayBuffer, 0, m_ActualSize * sizeof( Type ) ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CDynamicArray::DebugPrint Description: Prints the array to std output for debug only Input: void Output: void \*****************************************************************************/ template void CDynamicArrayType::DebugPrint( void ) const { #ifdef _DEBUG DPF( GFXDBG_STDLIB, "%s\n", __FUNCTION__ ); DPF( GFXDBG_STDLIB, "\tAddress = %p\n", this ); if( m_pArrayBuffer ) { for( DWORD i = 0; i < GetSize(); i++ ) { Type element = GetElement(i); DPF( GFXDBG_STDLIB, "\t\tElement[%u] = 0x%08x\n", i, *(DWORD*)&element ); } } #endif } /*****************************************************************************\ Function: CDynamicArray::operator= Description: Equal operator to copy an array Input: const CDynamicArrayType& array - array to copy Output: *this \*****************************************************************************/ template CDynamicArrayType& CDynamicArrayType::operator= ( const CDynamicArrayType &array ) { ACQUIRE_DEBUG_MUTEX_WRITE (m_InstanceNotThreadSafe); // TO DO: // Not all cases guarantee to be l=r after assignment: // // 1. array.m_pArrayBuffer == NULL // Probably lack of: // m_UsedSize = 0; // // 2. array.m_UsedSize == 0 // if (m_UsedSize < 0) -> always false, CreateArray not called // Probably lack of: // m_UsedSize = 0; // // 3. m_UsedSize >= array.m_UsedSize // First 'if' is false, CreateArray not called // Probably lack of: // m_UsedSize = array.m_UsedSize; if ( array.m_pArrayBuffer ) { if (m_UsedSize < array.m_UsedSize) { CreateArray( array.m_UsedSize ); } if (m_pArrayBuffer && (m_UsedSize >= array.m_UsedSize)) { MemCopy (m_pArrayBuffer, array.m_pArrayBuffer, array.m_UsedSize*sizeof(Type)); } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return *this; } /*****************************************************************************\ Function: CDynamicArray::CreateArray Description: Creates the internal array structure of the specified size Input: const DWORD size - number of elements Output: void \*****************************************************************************/ template void CDynamicArrayType::CreateArray( const DWORD size ) { if( size ) { if( size > GetMaxSize() ) { // Grow the array exponentially DWORD actualSize = GetMaxSize() * 2; if( size > actualSize ) { // The minimum allocation size is 32 elements, and // the allocations size is in multiples of 32 elements actualSize = Round( Max( size, 32 ), 32 ); } ASSERT( actualSize >= size ); ASSERT( actualSize > m_ActualSize ); const DWORD allocSize = actualSize * sizeof(Type); Type* pArrayBuffer = (Type*)CAllocatorType::Allocate( allocSize ); if( pArrayBuffer ) { SafeMemSet( pArrayBuffer, 0, allocSize ); if( m_pArrayBuffer ) { MemCopy( pArrayBuffer, m_pArrayBuffer, m_UsedSize * sizeof(Type) ); DeleteArray(); } m_pArrayBuffer = pArrayBuffer; m_ActualSize = actualSize; m_UsedSize = size; } } else { // Update the array length m_UsedSize = size; } } } /*****************************************************************************\ Function: CDynamicArray::PreAllocate Description: Pre-Allocates more space Input: const DWORD size - number of elements Output: void \*****************************************************************************/ template void CDynamicArrayType::PreAllocate( const DWORD size ) { if( size && ( size > GetMaxSize() ) ) { // Grow the array exponentially DWORD actualSize = GetMaxSize() * 2; if( size > actualSize ) { // The minimum allocation size is 32 elements, and // the allocations size is in multiples of 32 elements actualSize = Round( Max( size, 32 ), 32 ); } ASSERT( actualSize >= size ); ASSERT( actualSize > m_ActualSize ); const DWORD allocSize = actualSize * sizeof(Type); Type* pArrayBuffer = (Type*)CAllocatorType::Allocate( allocSize ); if( pArrayBuffer ) { SafeMemSet( pArrayBuffer, 0, allocSize ); if( m_pArrayBuffer ) { MemCopy( pArrayBuffer, m_pArrayBuffer, m_UsedSize * sizeof(Type) ); DeleteArray(); } m_pArrayBuffer = pArrayBuffer; m_ActualSize = actualSize; } } } /*****************************************************************************\ Function: CDynamicArray::DeleteArray Description: Deletes the internal array structure Input: void Output: void \*****************************************************************************/ template void CDynamicArrayType::DeleteArray( void ) { if( m_pArrayBuffer ) { CAllocatorType::Deallocate( m_pArrayBuffer ); m_pArrayBuffer = NULL; } m_ActualSize = 0; } /*****************************************************************************\ Function: CDynamicArray::GetMaxSize Description: Returns the maximum number of elements in the array Input: void Output: DWORD length \*****************************************************************************/ template DWORD CDynamicArrayType::GetMaxSize( void ) const { return m_ActualSize; } /*****************************************************************************\ Function: CDynamicArray::IsValidIndex Description: Determines if the index is in the array Input: const DWORD index Output: bool \*****************************************************************************/ template bool CDynamicArrayType::IsValidIndex( const DWORD index ) const { return ( index < GetSize() ); } /*****************************************************************************\ Class: CArray Description: Implements a dynamically-sized array, with "free-index" tracking \*****************************************************************************/ template class CArray : public CDynamicArray { public: CArray( const DWORD initSize ); virtual ~CArray( void ); bool SetElement( const DWORD index, const Type& element ); bool Resize( const DWORD size ); void SetFreeIndex( const DWORD index ); DWORD GetFreeIndex( void ); void Delete( void ); protected: virtual void CreateArray( const DWORD size ); typedef CQueue CFreeIndexQueue; void DeleteFreeIndexQueue( void ); CFreeIndexQueue* m_pFreeIndexQueue; DWORD m_FreeIndex; }; /*****************************************************************************\ Function: CArray Constructor Description: Initializes the array Input: const DWORD initSize - initial size of the array, in elements Output: none \*****************************************************************************/ template CArrayType::CArray( const DWORD initSize ) : CDynamicArrayType( initSize ) { m_pFreeIndexQueue = NULL; m_FreeIndex = 0; } /*****************************************************************************\ Function: CArray Destructor Description: Frees all internal dynamic memory Input: none Output: none \*****************************************************************************/ template CArrayType::~CArray( void ) { DeleteFreeIndexQueue(); } /*****************************************************************************\ Function: CArray::SetElement Description: Sets the element at the index in the array to the given element Input: const DWORD index - index of element to reference const Type& element - value of element to set Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CArrayType::SetElement( const DWORD index, const Type& element ) { bool success = CDynamicArrayType::SetElement( index, element ); if( success ) { m_FreeIndex = Max( index+1, m_FreeIndex ); #ifdef _DEBUG if( m_pFreeIndexQueue != NULL ) { ASSERT( m_pFreeIndexQueue->Find( index ) == m_pFreeIndexQueue->End() ); } #endif } return success; } /*****************************************************************************\ Function: CArray::Resize Description: Resize the array Input: const DWORD size - new size for the array Output: bool \*****************************************************************************/ template bool CArrayType::Resize( const DWORD size ) { bool success = CDynamicArrayType::Resize( size ); if( success ) { DeleteFreeIndexQueue(); } return success; } /*****************************************************************************\ Function: CArray::SetFreeIndex Description: Sets the index as unused by the client Input: const DWORD index - index of entry no longer used Output: none \*****************************************************************************/ template void CArrayType::SetFreeIndex( const DWORD index ) { if( !m_pFreeIndexQueue ) { m_pFreeIndexQueue = new CFreeIndexQueue(); ASSERT( m_pFreeIndexQueue ); } if( m_pFreeIndexQueue ) { m_pFreeIndexQueue->Push( index ); } } /*****************************************************************************\ Function: CArray::GetFreeIndex Description: Returns the index of unused entry Input: void Output: DWORD index \*****************************************************************************/ template DWORD CArrayType::GetFreeIndex( void ) { DWORD index = 0; if( m_pFreeIndexQueue && !m_pFreeIndexQueue->IsEmpty() ) { index = m_pFreeIndexQueue->Pop(); ASSERT( index < m_FreeIndex ); } else { index = m_FreeIndex++; if( m_pFreeIndexQueue ) { ASSERT( ( m_pFreeIndexQueue->Find( index ) == m_pFreeIndexQueue->End() ) ); } } ASSERT( index <= this->GetSize() ); return index; } /*****************************************************************************\ Function: CArray::Delete Description: Deletes the internal data Input: void Output: void \*****************************************************************************/ template void CArrayType::Delete( void ) { CDynamicArrayType::Delete(); DeleteFreeIndexQueue(); m_FreeIndex = 0; } /*****************************************************************************\ Function: CArray::CreateArray Description: Creates the internal array structure of the specified size Input: const DWORD size - number of elements Output: void \*****************************************************************************/ template void CArrayType::CreateArray( const DWORD size ) { CDynamicArrayType::CreateArray( size ); } /*****************************************************************************\ Function: CArray::DeleteFreeIndexQueue Description: Deletes the internal free index queue Input: void Output: void \*****************************************************************************/ template void CArrayType::DeleteFreeIndexQueue( void ) { if( m_pFreeIndexQueue ) { while( !m_pFreeIndexQueue->IsEmpty() ) { m_pFreeIndexQueue->Pop(); } SafeDelete( m_pFreeIndexQueue ); } } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/BinaryTree.h000066400000000000000000001155101363533017100246050ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #include "Stack.h" #include "String.h" namespace iSTD { /*****************************************************************************\ Struct: IsBinaryTreeTypeSupported \*****************************************************************************/ template struct IsBinaryTreeTypeSupported { enum { value = false }; }; template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; #ifndef __LP64__ // u/long on linux64 platform is 64-bit type and collides with U/INT64 template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; #endif template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; template<> struct IsBinaryTreeTypeSupported { enum { value = true }; }; template struct IsBinaryTreeTypeSupported { enum { value = true }; }; /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define BinaryTreeTemplateList class KeyType, class ElementType, class CAllocatorType #define CBinaryTreeType CBinaryTree /*****************************************************************************\ Class: CBinaryTree Description: Represents an unbalanced binary search tree \*****************************************************************************/ template class CBinaryTree : public CObject { public: CBinaryTree( void ); virtual ~CBinaryTree( void ); bool Add( const KeyType &key, const ElementType &element ); bool Get( const KeyType &key, ElementType &element ) const; bool GetNext( KeyType &key, ElementType &element ); bool GetMin( ElementType &element ) const; bool GetMax( ElementType &element ) const; bool GetMin( KeyType &key, ElementType &element ) const; bool GetMax( KeyType &key, ElementType &element ) const; bool Remove( const KeyType &key ); bool Remove( const KeyType &key, ElementType &element ); bool RemoveMin( ElementType &element ); bool RemoveMax( ElementType &element ); bool RemoveMin( KeyType &key, ElementType &element ); bool RemoveMax( KeyType &key, ElementType &element ); void RemoveAll( void ); bool IsEmpty( void ) const; DWORD GetCount( void ) const; void DebugPrint( void ) const; C_ASSERT( IsBinaryTreeTypeSupported::value == true ); protected: struct SNode { KeyType m_Key; ElementType m_Element; #ifdef _DEBUG DWORD m_GetCount; #endif SNode* m_RightNode; SNode* m_LeftNode; }; bool AddElement( SNode* &pTree, const KeyType &key, const ElementType &element ); bool GetElement( SNode* pTree, const KeyType &key, ElementType &element ) const; bool GetMinElement( SNode* pTree, KeyType &key, ElementType &element ) const; bool GetMaxElement( SNode* pTree, KeyType &key, ElementType &element ) const; bool GetNextElement( SNode* pTree, KeyType &key, ElementType &element ); bool RemoveElement( SNode* &pTree, const KeyType &key, ElementType &element ); bool RemoveMinElement( SNode* &pTree, KeyType &key, ElementType &element ); bool RemoveMaxElement( SNode* &pTree, KeyType &key, ElementType &element ); bool AddTree( SNode* &pTree, SNode* pNewTree ); void DeleteTree( SNode* &pTree ); void DebugPrintTree( const SNode* pTree, const DWORD depth ) const; SNode* CreateNode( const KeyType &key, const ElementType &element ); SNode* RemoveMinNode( SNode* &pTree ); SNode* RemoveMaxNode( SNode* &pTree ); void DeleteNode( SNode* &pNode ); SNode* m_pTree; DWORD m_Count; #ifdef _DEBUG DWORD m_AddCount; DWORD m_RemoveCount; DWORD m_MaxDepth; #endif DECL_DEBUG_MUTEX( m_InstanceNotThreadSafe ) }; /*****************************************************************************\ Function: CBinaryTree Constructor Description: Initializes internal data Input: none Output: none \*****************************************************************************/ template CBinaryTreeType::CBinaryTree( void ) : CObject() { m_pTree = NULL; m_Count = 0; #ifdef _DEBUG m_AddCount = 0; m_RemoveCount = 0; m_MaxDepth = 0; #endif INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBinaryTree Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template CBinaryTreeType::~CBinaryTree( void ) { DeleteTree( m_pTree ); DELETE_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBinaryTree::Add Description: Adds an element to the binary tree Input: const KeyType &key - key which determines sorting order of element const ElementType &element - element to add to binary tree Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::Add( const KeyType &key, const ElementType &element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); const bool success = AddElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::Get Description: Gets the element in the binary tree Input: const KeyType &key - key which determines sorting order of element Output: ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::Get( const KeyType &key, ElementType &element ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); const bool success = GetElement( m_pTree, key, element ); RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::GetMin Description: Gets the "minimum" element in the binary tree Input: none Output: ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetMin( ElementType &element ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); KeyType key; const bool success = GetMinElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::GetMax Description: Gets the "maximum" element in the binary tree Input: none Output: ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetMax( ElementType &element ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); KeyType key; const bool success = GetMaxElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::GetNext Description: Gets the next element in the binary tree Input: none Output: ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetNext( KeyType &key, ElementType &element ) { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); const bool success = GetNextElement( m_pTree, key, element ); RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::GetMin Description: Gets the "minimum" element in the binary tree Input: none Output: KeyType &key - key of the minimum element ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetMin( KeyType &key, ElementType &element ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); const bool success = GetMinElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::GetMax Description: Gets the "maximum" element in the binary tree Input: none Output: KeyType &key - key of the minimum element ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetMax( KeyType &key, ElementType &element ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); const bool success = GetMaxElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::Remove Description: Removes an element from the binary tree Input: const KeyType &key - key which determines sorting order of element Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::Remove( const KeyType &key ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); ElementType element; const bool success = RemoveElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::Remove Description: Removes an element from the binary tree Input: const KeyType &key - key which determines sorting order of element Output: ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::Remove( const KeyType &key, ElementType &element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); const bool success = RemoveElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::RemoveMin Description: Removes the minimum element from the binary tree Input: none Output: ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::RemoveMin( ElementType &element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); KeyType key; const bool success = RemoveMinElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::RemoveMax Description: Removes the maximum element from the binary tree Input: none Output: ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::RemoveMax( ElementType &element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); KeyType key; const bool success = RemoveMaxElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::RemoveMin Description: Removes the minimum element from the binary tree Input: none Output: KeyType &key - key of the minimum element ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::RemoveMin( KeyType &key, ElementType &element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); const bool success = RemoveMinElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::RemoveMax Description: Removes the maximum element from the binary tree Input: none Output: KeyType &key - key of the minimum element ElementType &element - element in binary tree bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::RemoveMax( KeyType &key, ElementType &element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); const bool success = RemoveMaxElement( m_pTree, key, element ); ASSERT( success ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CBinaryTree::RemoveAll Description: Removes all elements from the binary tree Input: void Output: void \*****************************************************************************/ template void CBinaryTreeType::RemoveAll( void ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); DeleteTree( m_pTree ); #ifdef _DEBUG m_RemoveCount += m_Count; #endif m_Count = 0; RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBinaryTree::IsEmpty Description: Determines if the binary tree is empty Input: void Output: bool \*****************************************************************************/ template bool CBinaryTreeType::IsEmpty( void ) const { const bool isEmpty = ( m_pTree == NULL ); return isEmpty; } /*****************************************************************************\ Function: CBinaryTree::GetCount Description: Returns the number of nodes in the tree Input: void Output: DWORD \*****************************************************************************/ template DWORD CBinaryTreeType::GetCount( void ) const { const DWORD count = m_Count; return count; } /*****************************************************************************\ Function: CBinaryTree::DebugPrint Description: Prints the tree to std output for debug only Input: void Output: void \*****************************************************************************/ template void CBinaryTreeType::DebugPrint( void ) const { #ifdef _DEBUG if( m_pTree ) { DPF( GFXDBG_STDLIB, "%s\n", __FUNCTION__ ); DPF( GFXDBG_STDLIB, "\tAddress = %p\n", this ); DPF( GFXDBG_STDLIB, "\tCount = %d\n", m_Count ); DPF( GFXDBG_STDLIB, "\tAddCount = %d\n", m_AddCount ); DPF( GFXDBG_STDLIB, "\tRemoveCount = %d\n", m_RemoveCount ); DPF( GFXDBG_STDLIB, "\tMaxDepth = %d\n", m_MaxDepth ); DebugPrintTree( m_pTree, 0 ); } #endif } /*****************************************************************************\ Function: CBinaryTree::AddElement Description: Adds an element to the tree Input: SNode* &pTree - pointer to tree to add element const KeyType &key - key which determines sorting order of element const ElementType &element - element to add Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::AddElement( SNode* &pTree, const KeyType &key, const ElementType &element ) { SNode** ppNode = &pTree; SNode* pNode = *ppNode; #ifdef _DEBUG DWORD depth = 1; #endif while( pNode ) { // Two elements should not have the same key if( pNode->m_Key == key ) { if( pNode->m_Element == element ) { // the identical node already exists in the tree return true; } else { ASSERT(0); return false; } } // Add element to left sub-tree else if( key < pNode->m_Key ) { ppNode = &(pNode->m_LeftNode); #ifdef _DEBUG ++depth; #endif } // Add element to right sub-tree else { ppNode = &(pNode->m_RightNode); #ifdef _DEBUG ++depth; #endif } pNode = *ppNode; } pNode = CreateNode( key, element ); if( pNode ) { *ppNode = pNode; #ifdef _DEBUG ++m_AddCount; m_MaxDepth = iSTD::Max( m_MaxDepth, depth ); #endif return true; } else { return false; } } /*****************************************************************************\ Function: CBinaryTree::GetElement Description: Gets the element from a tree Input: SNode* pTree - pointer to tree to search const KeyType &key - key which determines sorting order of element Output: ElementType &element - element found bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetElement( SNode* pTree, const KeyType &key, ElementType &element ) const { SNode* pNode = pTree; while( pNode ) { // Do keys match? if( pNode->m_Key == key ) { // Element found element = pNode->m_Element; #ifdef _DEBUG pNode->m_GetCount++; #endif return true; } // Search left sub-tree else if( key < pNode->m_Key ) { pNode = pNode->m_LeftNode; } // Search right sub-tree else { pNode = pNode->m_RightNode; } } // Could not find the element return false; } /*****************************************************************************\ Function: CBinaryTree::GetMinElement Description: Gets the "minimum" element from a sub-tree Input: SNode* pTree - pointer to sub-tree to search Output: KeyType &key - key of element ElementType &element - element found bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetMinElement( SNode* pTree, KeyType &key, ElementType &element ) const { SNode* pNode = pTree; while( pNode ) { if( pNode->m_LeftNode ) { pNode = pNode->m_LeftNode; } else { key = pNode->m_Key; element = pNode->m_Element; #ifdef _DEBUG pNode->m_GetCount++; #endif return true; } } return false; } /*****************************************************************************\ Function: CBinaryTree::GetMaxElement Description: Gets the "maximum" element from a sub-tree Input: SNode* pTree - pointer to sub-tree to search Output: KeyType &key - key of element ElementType &element - element found bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetMaxElement( SNode* pTree, KeyType &key, ElementType &element ) const { SNode* pNode = pTree; while( pNode ) { if( pNode->m_RightNode ) { pNode = pNode->m_RightNode; } else { key = pNode->m_Key; element = pNode->m_Element; #ifdef _DEBUG pNode->m_GetCount++; #endif return true; } } return false; } /*****************************************************************************\ Function: CBinaryTree::GetNextElement Description: Gets the next element from a sub-tree Input: SNode* pTree - pointer to sub-tree to search Output: KeyType &key - key of element ElementType &element - element found bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::GetNextElement( SNode* pTree, KeyType &key, ElementType &element ) { static const DWORD prev_count = 1024; DWORD prev_pos = 0; SNode* pNode = pTree; SNode* prev[ prev_count ]; prev[ prev_pos ] = 0; while( pNode ) { // Do keys match? if( pNode->m_Key == key ) { // Element found if( pNode->m_RightNode ) { // there is right child - return it or leftmost node of it's subtree pNode = pNode->m_RightNode; while( pNode->m_LeftNode ) { pNode = pNode->m_LeftNode; } key = pNode->m_Key; element = pNode->m_Element; return true; } else { // there is no right child // must traverse up as long as node is right child of it's parent // ...and parent is not NULL while( prev[ prev_pos ]!=0 && prev[ prev_pos ]->m_RightNode == pNode ) { pNode = prev[ prev_pos ]; --prev_pos; } if( prev[ prev_pos ]==0 ) { // node is root - there is no 'next' return false; } else { // node is not root - it has to be left child of it's parent key = prev[ prev_pos ]->m_Key; element = prev[ prev_pos ]->m_Element; return true; } } } // Search left sub-tree else if( key < pNode->m_Key ) { ++prev_pos; ASSERT( prev_pos < prev_count ); prev[ prev_pos ] = pNode; pNode = pNode->m_LeftNode; } // Search right sub-tree else { ++prev_pos; ASSERT( prev_pos < prev_count ); prev[ prev_pos ] = pNode; pNode = pNode->m_RightNode; } } // Could not find the element return false; } /*****************************************************************************\ Function: CBinaryTree::RemoveElement Description: Deletes the element from a sub-tree Input: SNode* &pTree - pointer to sub-tree to search const KeyType &key - key which determines sorting order of element Output: ElementType &element - element found bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::RemoveElement( SNode* &pTree, const KeyType &key, ElementType &element ) { SNode** ppNode = &pTree; SNode* pNode = *ppNode; while( pNode ) { // Do keys match? if( pNode->m_Key == key ) { // Cache the pointer to the node containing the element SNode* pRemoveNode = pNode; if( pRemoveNode->m_LeftNode && pRemoveNode->m_RightNode ) { pNode = RemoveMaxNode( pRemoveNode->m_LeftNode ); ASSERT( pNode ); if( pNode ) { ASSERT( pNode->m_LeftNode == NULL ); pNode->m_LeftNode = pRemoveNode->m_LeftNode; ASSERT( ( pNode->m_LeftNode ) ? !( pNode->m_Key < pNode->m_LeftNode->m_Key ) : 1 ); ASSERT( pNode->m_RightNode == NULL ); pNode->m_RightNode = pRemoveNode->m_RightNode; ASSERT( ( pNode->m_RightNode ) ? ( pNode->m_Key < pNode->m_RightNode->m_Key ) : 1 ); } pRemoveNode->m_LeftNode = NULL; pRemoveNode->m_RightNode = NULL; } else if( pRemoveNode->m_LeftNode ) { pNode = pRemoveNode->m_LeftNode; pRemoveNode->m_LeftNode = NULL; } else if( pRemoveNode->m_RightNode ) { pNode = pRemoveNode->m_RightNode; pRemoveNode->m_RightNode = NULL; } else { pNode = NULL; } // Return the element element = pRemoveNode->m_Element; // Delete the node DeleteNode( pRemoveNode ); *ppNode = pNode; #ifdef _DEBUG ++m_RemoveCount; #endif return true; } // Search left sub-tree else if( key < pNode->m_Key ) { ppNode = &(pNode->m_LeftNode); } // Search right sub-tree else { ppNode = &(pNode->m_RightNode); } pNode = *ppNode; } return false; } /*****************************************************************************\ Function: CBinaryTree::RemoveMinElement Description: Deletes the minimum element from a sub-tree Input: SNode* &pTree - pointer to sub-tree to search Output: KeyType &key - key of element ElementType &element - element found bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::RemoveMinElement( SNode* &pTree, KeyType &key, ElementType &element ) { SNode** ppNode = &pTree; SNode* pNode = *ppNode; while( pNode ) { if( pNode->m_LeftNode ) { ppNode = &(pNode->m_LeftNode); pNode = *ppNode; } else { // Cache the pointer to the node containing the element SNode* pRemoveNode = pNode; pNode = pRemoveNode->m_RightNode; pRemoveNode->m_RightNode = NULL; // Return the key and element key = pRemoveNode->m_Key; element = pRemoveNode->m_Element; // Delete the node DeleteNode( pRemoveNode ); *ppNode = pNode; #ifdef _DEBUG ++m_RemoveCount; #endif return true; } } return false; } /*****************************************************************************\ Function: CBinaryTree::RemoveMaxElement Description: Deletes the maximum element from a sub-tree Input: SNode* &pTree - pointer to sub-tree to search Output: KeyType &key - key of element ElementType &element - element found bool - SUCCESS or FAIL \*****************************************************************************/ template bool CBinaryTreeType::RemoveMaxElement( SNode* &pTree, KeyType &key, ElementType &element ) { SNode** ppNode = &pTree; SNode* pNode = *ppNode; while( pNode ) { if( pNode->m_RightNode ) { ppNode = &(pNode->m_RightNode); pNode = *ppNode; } else { // Cache the pointer to the node containing the element SNode* pRemoveNode = pNode; pNode = pRemoveNode->m_LeftNode; pRemoveNode->m_LeftNode = NULL; // Return the key and element key = pRemoveNode->m_Key; element = pRemoveNode->m_Element; // Delete the node DeleteNode( pRemoveNode ); *ppNode = pNode; #ifdef _DEBUG ++m_RemoveCount; #endif return true; } } return false; } /*****************************************************************************\ Function: CBinaryTree::AddTree Description: Adds a sub-tree Input: SNode* &pTree - pointer to sub-tree to add to SNode* &pNewTree - pointer to sub-tree to add Output: bool \*****************************************************************************/ template bool CBinaryTreeType::AddTree( SNode* &pTree, SNode* pNewTree ) { SNode** ppNode = &pTree; SNode* pNode = *ppNode; while( pNode ) { // Two elements should not have the same key if( pNode->m_Key == pNewTree->m_Key ) { ASSERT( pNode->m_Element == pNewTree->m_Element ); return false; } // Add element to left sub-tree else if( pNewTree->m_Key < pNode->m_Key ) { ppNode = &(pNode->m_LeftNode); } // Add element to right sub-tree else { ppNode = &(pNode->m_RightNode); } pNode = *ppNode; } *ppNode = pNewTree; return true; } /*****************************************************************************\ Function: CBinaryTree::DeleteTree Description: Recursive function to delete a sub-tree Input: SNode* &pTree - pointer to sub-tree to delete Output: void \*****************************************************************************/ template void CBinaryTreeType::DeleteTree( SNode* &pTree ) { while( pTree ) { SNode* pNode = RemoveMinNode( pTree ); DeleteNode( pNode ); } } /*****************************************************************************\ Function: CBinaryTree::DebugPrintTree Description: Recursive function to debug a sub-tree Input: const SNode* tree - pointer to sub-tree to debug const DWORD depth - current node depth Output: void \*****************************************************************************/ template void CBinaryTreeType::DebugPrintTree( const SNode* pTree, const DWORD depth ) const { #ifdef _DEBUG if( pTree ) { // Debug right sub-tree if( pTree->m_RightNode ) { DebugPrintTree( pTree->m_RightNode, depth + 1 ); } iSTD::CString strIndent; strIndent = "\t"; DWORD i = 0; for( i = 0; i < depth; ++i ) { strIndent += " "; } iSTD::CString strKeyData; strKeyData = "{ "; //DWORD* pKeyData = (DWORD*)&(pTree->m_Key); //for( i = 0; i < sizeof(KeyType) / sizeof(DWORD); ++i ) //{ // strKeyData.AppendFormatted( "0x%08x ", pKeyData[i] ); //} strKeyData += "}"; iSTD::CString strElementData; strElementData = "{ "; //DWORD* pElementData = (DWORD*)&(pTree->m_Element); //for( i = 0; i < sizeof(ElementType) / sizeof(DWORD); ++i ) //{ // strElementData.AppendFormatted( "0x%08x ", pElementData[i] ); //} strElementData += "}"; DPF( GFXDBG_STDLIB, "%sBinaryTreeNode[%u].Key = %s\n", (const char*)strIndent, depth, (const char*)strKeyData ); DPF( GFXDBG_STDLIB, "%sBinaryTreeNode[%u].Element = %s\n", (const char*)strIndent, depth, (const char*)strElementData ); DPF( GFXDBG_STDLIB, "%sBinaryTreeNode[%u].GetCount = %d\n", (const char*)strIndent, depth, pTree->m_GetCount ); // Debug left sub-tree if( pTree->m_LeftNode ) { DebugPrintTree( pTree->m_LeftNode, depth + 1 ); } } #endif } /*****************************************************************************\ Function: CBinaryTree::CreateNode Description: Creates a node Input: const KeyType &key - key which determines sorting order of element const ElementType &element - element in binary tree Output: SNode* - node created \*****************************************************************************/ template typename CBinaryTreeType::SNode* CBinaryTreeType::CreateNode( const KeyType &key, const ElementType &element ) { // Create node to add element here SNode* pNode = (SNode*)CAllocatorType::Allocate( sizeof(SNode) ); ASSERT( pNode ); if( pNode ) { pNode->m_Key = key; pNode->m_Element = element; pNode->m_RightNode = NULL; pNode->m_LeftNode = NULL; #ifdef _DEBUG pNode->m_GetCount = 0; #endif ++m_Count; } return pNode; } /*****************************************************************************\ Function: CBinaryTree::RemoveMinNode Description: Removes the min node from the tree Input: SNode* &pTree - tree to remove min node from Output: SNode* - node removed \*****************************************************************************/ template typename CBinaryTreeType::SNode* CBinaryTreeType::RemoveMinNode( SNode* &pTree ) { SNode** ppNode = &pTree; SNode* pNode = *ppNode; while( pNode ) { if( pNode->m_LeftNode ) { ppNode = &(pNode->m_LeftNode); pNode = *ppNode; } else { // Cache the pointer to the node containing the element SNode* pRemoveNode = pNode; pNode = pRemoveNode->m_RightNode; pRemoveNode->m_RightNode = NULL; *ppNode = pNode; return pRemoveNode; } } return NULL; } /*****************************************************************************\ Function: CBinaryTree::RemoveMaxNode Description: Removes the max node from the tree Input: SNode* &pTree - tree to remove max node from Output: SNode* - node removed \*****************************************************************************/ template typename CBinaryTreeType::SNode* CBinaryTreeType::RemoveMaxNode( SNode* &pTree ) { SNode** ppNode = &pTree; SNode* pNode = *ppNode; while( pNode ) { if( pNode->m_RightNode ) { ppNode = &(pNode->m_RightNode); pNode = *ppNode; } else { // Cache the pointer to the node containing the element SNode* pRemoveNode = pNode; pNode = pRemoveNode->m_LeftNode; pRemoveNode->m_LeftNode = NULL; *ppNode = pNode; return pRemoveNode; } } return NULL; } /*****************************************************************************\ Function: CBinaryTree::DeleteNode Description: Deletes a node Input: SNode* node - node to delete Output: void \*****************************************************************************/ template void CBinaryTreeType::DeleteNode( SNode* &pNode ) { CAllocatorType::Deallocate( pNode ); --m_Count; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/BitSet.h000066400000000000000000001227201363533017100237340ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #include "utility.h" #include "MemCopy.h" #include "Threading.h" namespace iSTD { /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define BitSetTemplateList class CAllocatorType #define CBitSetType CBitSet /*****************************************************************************\ Struct: TPtrSize Description: Defines type that is size of a pointer. It also provides a set of static functions for managing on bits, depending on pointer size. \*****************************************************************************/ template struct TPtrSize { }; // Specialization for 32bit pointers: template <> struct TPtrSize<4> { typedef unsigned int type; static inline type Bit( const DWORD index ) { return BIT( index ); } static inline DWORD Bsf( const type mask ) { return iSTD::bsf( mask ); } static inline DWORD Bsr( const type mask ) { return iSTD::bsr( mask ); } static inline DWORD Count( const type mask ) { return iSTD::BitCount( mask ); } }; // Specialization for 64bit pointers: template <> struct TPtrSize<8> { typedef unsigned long long type; static inline type Bit( const DWORD index ) { return QWBIT( index ); } static inline DWORD Bsf( const type mask ) { #if defined( _WIN64 ) || defined( __x86_64__ ) return iSTD::bsf64( mask ); #else // Should never compile this code - added to get rid of compilation // warnings on GCC. ASSERT( 0 ); return 0; #endif } static inline DWORD Bsr( const type mask ) { #if defined( _WIN64 ) || defined( __x86_64__ ) return iSTD::bsr64( mask ); #else // Should never compile this code - added to get rid of compilation // warnings on GCC. ASSERT( 0 ); return 0; #endif } static inline DWORD Count( const type mask ) { return iSTD::BitCount64( mask ); } }; /*****************************************************************************\ Class: CBitSet Description: Implements a dynamic bit set. For sets smaller than size of pointer, bits are stored in a pointer to the array, to prevent dynamic allocations. \*****************************************************************************/ template class CBitSet : public CObject { private: static const DWORD BITS_PER_BYTE = 8; typedef DWORD BITSET_ARRAY_TYPE; static const DWORD cBitsPerArrayElement = sizeof( BITSET_ARRAY_TYPE ) * BITS_PER_BYTE; static const DWORD cBitsInPtr = sizeof(BITSET_ARRAY_TYPE*) * 8; typedef TPtrSize CPtrSize; typedef CPtrSize::type bitptr_t; public: CBitSet( void ); CBitSet( DWORD size ); CBitSet( const CBitSetType& other ); virtual ~CBitSet( void ); void Resize( DWORD size ); void Clear( void ); void SetAll( void ); void Invert( void ); bool IsEmpty() const; bool IsEmpty( DWORD start, DWORD length ) const; bool IsSet( DWORD index ) const; bool Intersects( const CBitSetType& other ) const; DWORD GetNextMember( DWORD start ) const; void Set( DWORD index ); void Set( const CBitSetType& other ); void UnSet( DWORD index ); void UnSet( const CBitSetType& other ); DWORD GetSize( void ) const; DWORD BitCount( void ) const; DWORD BitCount( DWORD limit ) const; long Min( void ) const; long Max( void ) const; template T ConvertTo() const; bool operator==( const CBitSetType& other ) const; bool operator!=( const CBitSetType& other ) const; CBitSetType& operator= ( const CBitSetType& other ); CBitSetType& operator|= ( const CBitSetType& other ); CBitSetType& operator&= ( const CBitSetType& other ); protected: // Depending on a set size, bits can be stored in dynamically allocated // memory, or in a pointer. union { BITSET_ARRAY_TYPE* m_BitSetArray; bitptr_t m_PtrBits; }; DWORD m_Size; void Create( DWORD size ); void Copy( const CBitSetType& other ); void Delete( void ); bool StoredInPtr( void ) const; bitptr_t GetActivePtrMask( void ) const; BITSET_ARRAY_TYPE* GetArrayPointer( void ); const BITSET_ARRAY_TYPE* GetArrayPointer( void ) const; DECL_DEBUG_MUTEX( m_InstanceNotThreadSafe ) }; /*****************************************************************************\ Function: CBitSet Constructor Description: Initializes the BitSet Input: none Output: none \*****************************************************************************/ template CBitSetType::CBitSet( void ) : CObject() { m_BitSetArray = NULL; m_Size = 0; INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet Constructor Description: Initializes the BitSet Input: DWORD size - initial size of the BitSet Output: none \*****************************************************************************/ template CBitSetType::CBitSet( DWORD size ) : CObject() { m_BitSetArray = NULL; m_Size = 0; INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe ); Create( size ); } /*****************************************************************************\ Function: CBitSet Copy Constructor Description: Initializes the BitSet Input: const CBitSetType& other - other bitset to copy Output: none \*****************************************************************************/ template CBitSetType::CBitSet( const CBitSetType& other ) : CObject() { m_BitSetArray = NULL; m_Size = 0; INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe ); Copy( other ); } /*****************************************************************************\ Function: CBitSet Destructor Description: Frees all internal dynamic memory Input: none Output: none \*****************************************************************************/ template CBitSetType::~CBitSet( void ) { Delete(); DELETE_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::Resize Description: Resizes the bitset Input: DWORD size - new size of the BitSet Output: none \*****************************************************************************/ template void CBitSetType::Resize( DWORD size ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); Create( size ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::Clear Description: Unsets all bits in the bitset Input: none Output: none \*****************************************************************************/ template void CBitSetType::Clear( void ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); if( StoredInPtr() ) { m_PtrBits = static_cast( 0 ); } else { const DWORD cArraySizeInBytes = ( m_Size + BITS_PER_BYTE - 1 ) / BITS_PER_BYTE; SafeMemSet( m_BitSetArray, 0, cArraySizeInBytes ); } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::SetAll Description: Sets all the bits in this bitset, from bit zero to bit "size". Note that any "extra" bits (bits that are part of the array but that are less than "size" are not set and remain unset. Input: void Output: void \*****************************************************************************/ template void CBitSetType::SetAll( void ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); if( StoredInPtr() ) { m_PtrBits = GetActivePtrMask(); } else { ASSERT( m_BitSetArray ); const DWORD cArraySize = ( m_Size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; const BITSET_ARRAY_TYPE cExtraBits = m_Size % cBitsPerArrayElement; const BITSET_ARRAY_TYPE cExtraBitMask = cExtraBits ? ( ( 1 << cExtraBits ) - 1 ) : ( ~0 ); DWORD index; for( index = 0; index < cArraySize - 1; index++ ) { m_BitSetArray[index] = ~((BITSET_ARRAY_TYPE)0); } if( index < cArraySize ) { m_BitSetArray[index] = ~((BITSET_ARRAY_TYPE)0) & cExtraBitMask; } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::Invert Description: Computes the inverse of this bitset. Note that any "extra" bits (bits that are part of the array but that are less than "size" are not inverted and remain un-set. Input: void Output: void \*****************************************************************************/ template void CBitSetType::Invert( void ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); if( StoredInPtr() ) { m_PtrBits = (~m_PtrBits) & GetActivePtrMask(); } else { ASSERT( m_BitSetArray ); const DWORD cArraySize = ( m_Size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; const BITSET_ARRAY_TYPE cExtraBits = m_Size % cBitsPerArrayElement; const BITSET_ARRAY_TYPE cExtraBitMask = cExtraBits ? ( ( 1 << cExtraBits ) - 1 ) : ( ~0 ); DWORD index; for( index = 0; index < cArraySize - 1; index++ ) { m_BitSetArray[index] = ~m_BitSetArray[index]; } if( index < cArraySize ) { m_BitSetArray[index] = ~m_BitSetArray[index] & cExtraBitMask; } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::IsEmpty Description: Determines if any bits are on in the bit set. Input: none Output: bool \*****************************************************************************/ template bool CBitSetType::IsEmpty( void ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); bool isEmpty = true; if( StoredInPtr() ) { isEmpty = ( m_PtrBits == static_cast( 0 ) ); } else { DWORD index = ( m_Size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; while( isEmpty && index-- ) { isEmpty = (m_BitSetArray[ index ] == 0 ); } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return isEmpty; } /*****************************************************************************\ Function: CBitSet::IsEmpty Description: Determines if any bits are set in the bit set in the specified range. Input: DWORD start - Start of the range to check, inclusive. DWORD length - Length of the range to check. Output: bool \*****************************************************************************/ template bool CBitSetType::IsEmpty( DWORD start, DWORD length ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); bool isEmpty = true; ASSERT( start < m_Size ); ASSERT( length != 0 ); ASSERT( start + length <= m_Size ); if( StoredInPtr() ) { const DWORD end = start + length; // Create a bit mask for this range: bitptr_t mask = ~( CPtrSize::Bit( start ) - 1 ); if( end < cBitsInPtr ) { mask &= CPtrSize::Bit( end ) - 1; } isEmpty = ( ( mask & m_PtrBits ) == static_cast( 0 ) ); } else { const DWORD end = start + length; const DWORD startArrayIndex = start / cBitsPerArrayElement; const DWORD endArrayIndex = ( end - 1 ) / cBitsPerArrayElement; const DWORD startBit = start % cBitsPerArrayElement; const DWORD endBit = end % cBitsPerArrayElement; const BITSET_ARRAY_TYPE startMask = ~( ( 1 << startBit ) - 1 ); const BITSET_ARRAY_TYPE endMask = endBit ? ( ( 1 << endBit ) - 1 ) : ~0; DWORD arrayIndex = startArrayIndex; BITSET_ARRAY_TYPE data = m_BitSetArray[ arrayIndex ]; data &= startMask; if( startArrayIndex == endArrayIndex ) { data &= endMask; isEmpty = ( data == 0 ); } else { isEmpty = ( data == 0 ); if( isEmpty ) { for( arrayIndex = arrayIndex + 1; arrayIndex < endArrayIndex && isEmpty; arrayIndex++ ) { data = m_BitSetArray[ arrayIndex ]; isEmpty = ( data == 0 ); } } if( isEmpty ) { data = m_BitSetArray[ endArrayIndex ]; data &= endMask; isEmpty = ( data == 0 ); } } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return isEmpty; } /*****************************************************************************\ Function: CBitSet::IsSet Description: Returns true if the bit at the specified index is set, false otherwise. Input: DWORD index - index of the bit to check Output: bool \*****************************************************************************/ template bool CBitSetType::IsSet( DWORD index ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); bool isSet = false; if( index < m_Size ) { if( StoredInPtr() ) { isSet = ( ( m_PtrBits & CPtrSize::Bit( index ) ) != static_cast( 0 ) ); } else { DWORD arrayIndex = index / cBitsPerArrayElement; DWORD bitIndex = index % cBitsPerArrayElement; isSet = ( ( m_BitSetArray[arrayIndex] & BIT(bitIndex) ) != 0 ); } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return isSet; } /*****************************************************************************\ Function: CBitSet::Intersects Description: Returns true if any bits are on in both this bit set and the passed-in bit set. This is a shortcut for ( BitSet1 & BitSet2 ).IsEmpty(). Input: CBitSetType other - Other bit set Output: bool \*****************************************************************************/ template bool CBitSetType::Intersects( const CBitSetType& other ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); bool intersects = false; if( StoredInPtr() && other.StoredInPtr() ) { intersects = ( ( m_PtrBits & other.m_PtrBits ) != static_cast( 0 ) ); } else { // Size of bitptr_t must be multiplicity of size of BITSET_ARRAY_TYPE. C_ASSERT( sizeof( bitptr_t ) % sizeof( BITSET_ARRAY_TYPE ) == 0 ); // If stored in pointer, get pointer to this pointer and use // common implementation: const BITSET_ARRAY_TYPE* ptrThis = GetArrayPointer(); const BITSET_ARRAY_TYPE* ptrOther = other.GetArrayPointer(); DWORD minSize = ( m_Size < other.m_Size ) ? m_Size : other.m_Size; DWORD index = ( minSize + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; while( !intersects && index-- ) { if( ( ptrThis[ index ] & ptrOther[ index ] ) != 0 ) { intersects = true; } } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return intersects; } /*****************************************************************************\ Function: CBitSet::GetNextMember Description: Gets the next member in the set, starting from the specified index. If there are no additional members in the set, returns the size of the set. Example usage pattern: for( DWORD value = bitSet.GetNextMember( 0 ); value < bitSet.GetSize(); value = bitSet.GetNextMember( ++value ) ) Input: DWORD start - Index to start the search Output: DWORD - The next member of the set, or the size of the set if there are no more members in the set. \*****************************************************************************/ template DWORD CBitSetType::GetNextMember( DWORD start ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); DWORD nextMember = m_Size; if( start < m_Size ) { if( StoredInPtr() ) { bitptr_t ptrBits = m_PtrBits; // Mask out bits to start: ptrBits &= ~( CPtrSize::Bit( start ) - 1 ); // Find first bit: if( ptrBits != static_cast( 0 ) ) { nextMember = CPtrSize::Bsf( ptrBits ); } } else { const DWORD startArrayIndex = start / cBitsPerArrayElement; const DWORD endArrayIndex = ( m_Size - 1 ) / cBitsPerArrayElement; const DWORD startBit = start % cBitsPerArrayElement; const DWORD endBit = m_Size % cBitsPerArrayElement; const BITSET_ARRAY_TYPE startMask = ~( ( 1 << startBit ) - 1 ); const BITSET_ARRAY_TYPE endMask = endBit ? ( ( 1 << endBit ) - 1 ) : ~0; DWORD arrayIndex = startArrayIndex; BITSET_ARRAY_TYPE data = m_BitSetArray[ arrayIndex ]; data &= startMask; if( arrayIndex == endArrayIndex ) { data &= endMask; } else { if( data == 0 ) { for( arrayIndex = arrayIndex + 1; arrayIndex < endArrayIndex; arrayIndex++ ) { data = m_BitSetArray[ arrayIndex ]; if( data != 0 ) { break; } } if( data == 0 ) { data = m_BitSetArray[ endArrayIndex ]; data &= endMask; } } } if( data != 0 ) { // Found, find the first bit that's on in "data". const DWORD lsb = bsf( data ); nextMember = ( arrayIndex * cBitsPerArrayElement ) + lsb; } } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return nextMember; } /*****************************************************************************\ Function: CBitSet::Set Description: Sets the bit at the given index. Input: DWORD index - index of the bit to set Output: void \*****************************************************************************/ template void CBitSetType::Set( DWORD index ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); // If the index is larger than the size of the BitSet then grow the BitSet if( index >= m_Size ) { Create( index + 1 ); } ASSERT( index < m_Size ); if( StoredInPtr() ) { m_PtrBits |= CPtrSize::Bit( index ); } else { DWORD arrayIndex = index / cBitsPerArrayElement; DWORD bitIndex = index % cBitsPerArrayElement; m_BitSetArray[arrayIndex] |= BIT(bitIndex); } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::Set Description: Sets all of the given bits. Input: CBitSetType other - bits to set. Output: void \*****************************************************************************/ template void CBitSetType::Set( const CBitSetType& other ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); DWORD size = other.m_Size; if( m_Size < other.m_Size ) { Create( other.m_Size ); size = m_Size; } ASSERT( m_Size >= other.m_Size ); if( StoredInPtr() ) { ASSERT( other.StoredInPtr() ); m_PtrBits |= other.m_PtrBits; } else { const BITSET_ARRAY_TYPE* pOtherArray = other.GetArrayPointer(); DWORD index = ( size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; while( index-- ) { m_BitSetArray[ index ] |= pOtherArray[ index ]; } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::UnSet Description: Un-Sets the bit at the given index. Input: DWORD index - index of the bit to un-set Output: void \*****************************************************************************/ template void CBitSetType::UnSet( DWORD index ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); // If the index is larger than the size of the BitSet then grow the BitSet if( index >= m_Size ) { Create( index + 1 ); if( index >= m_Size ) { // In case allocation failed... ASSERT( index < m_Size ); return; } } if( StoredInPtr() ) { m_PtrBits &= ( ~CPtrSize::Bit( index ) ) & GetActivePtrMask(); } else { DWORD arrayIndex = index / cBitsPerArrayElement; DWORD bitIndex = index % cBitsPerArrayElement; m_BitSetArray[arrayIndex] &= ~BIT(bitIndex); } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::UnSet Description: Un-Sets all of the given bits. Input: CBitSetType other - bits to un-set. Output: void \*****************************************************************************/ template void CBitSetType::UnSet( const CBitSetType& other ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); DWORD size = other.m_Size; if( m_Size < other.m_Size ) { Create( other.m_Size ); size = m_Size; } ASSERT( m_Size >= other.m_Size ); if( StoredInPtr() ) { ASSERT( other.StoredInPtr() ); m_PtrBits &= ~other.m_PtrBits; m_PtrBits &= GetActivePtrMask(); } else { const BITSET_ARRAY_TYPE* pOtherArray = other.GetArrayPointer(); DWORD index = ( size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; while( index-- ) { m_BitSetArray[ index ] &= ~pOtherArray[ index ]; } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CBitSet::GetSize Description: Returns the number of bits in the BitSet Input: void Output: DWORD length \*****************************************************************************/ template DWORD CBitSetType::GetSize( void ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); const DWORD size = m_Size; RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return size; } /*****************************************************************************\ Function: CBitSet::Min Description: Returns the minimum bit set Input: void Output: long \*****************************************************************************/ template long CBitSetType::Min( void ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); long minBit = -1; if( StoredInPtr() ) { if( m_PtrBits ) { minBit = CPtrSize::Bsf( m_PtrBits ); } } else { const DWORD count = ( m_Size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; for( DWORD i = 0; i < count; ++i ) { if( m_BitSetArray[i] != 0 ) { const DWORD lsb = bsf( m_BitSetArray[i] ); minBit = (i * cBitsPerArrayElement) + lsb; break; } } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return minBit; } /*****************************************************************************\ Function: CBitSet::Max Description: Returns the maximum bit set Input: void Output: long \*****************************************************************************/ template long CBitSetType::Max( void ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); long maxBit = -1; if( StoredInPtr() ) { if( m_PtrBits ) { maxBit = CPtrSize::Bsr( m_PtrBits ); } } else { const DWORD count = ( m_Size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; for( long i = count-1; i >= 0; --i ) { if( m_BitSetArray[i] != 0 ) { const DWORD msb = bsr( m_BitSetArray[i] ); maxBit = (i * cBitsPerArrayElement) + msb; break; } } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return maxBit; } /*****************************************************************************\ Function: template CBitSet::ConvertTo Description: Returns a T representation of the current bit set. Only valid if the bit set consists of less than (or equal to) sizeof(T) * BITS_PER_BYTE bits. It is expected that the types that bitsets get converted to will be BYTES, WORDS, or DWORDS, although other types may work as well. Input: void Output: T representation of the bitfield. \*****************************************************************************/ template template T CBitSetType::ConvertTo() const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); T mask = 0; if( StoredInPtr() ) { bitptr_t bits = m_PtrBits; mask = (T)( bits ); } else { ASSERT( m_BitSetArray ); mask = ((T*)m_BitSetArray)[0]; } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return mask; } /*****************************************************************************\ Function: CBitSet::operator == Description: Tests this bitset and another bitset for equality. Input: CBitSetType& other - other BitSet Output: bool \*****************************************************************************/ template bool CBitSetType::operator==( const CBitSetType& other ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); bool isEqual = false; if( m_Size == other.m_Size ) { ASSERT( this->StoredInPtr() == other.StoredInPtr() ); if( StoredInPtr() ) { isEqual = ( m_PtrBits == other.m_PtrBits ); } else { const DWORD cArraySizeInBytes = ( m_Size + BITS_PER_BYTE - 1 ) / BITS_PER_BYTE; isEqual = ( 0 == SafeMemCompare( m_BitSetArray, other.m_BitSetArray, cArraySizeInBytes ) ); } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return isEqual; } /*****************************************************************************\ Function: CBitSet::operator != Description: Tests this bitset and another bitset for inequality. Input: CBitSetType& other - other BitSet Output: bool \*****************************************************************************/ template bool CBitSetType::operator!=( const CBitSetType& other ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); bool isNotEqual = true; if( m_Size == other.m_Size ) { ASSERT( this->StoredInPtr() == other.StoredInPtr() ); if( StoredInPtr() ) { isNotEqual = ( m_PtrBits != other.m_PtrBits ); } else { const DWORD cArraySizeInBytes = ( m_Size + BITS_PER_BYTE - 1 ) / BITS_PER_BYTE; isNotEqual = ( 0 != SafeMemCompare( m_BitSetArray, other.m_BitSetArray, cArraySizeInBytes ) ); } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return isNotEqual; } /*****************************************************************************\ Function: CBitSet::operator = Description: Equal operator to copy a BitSet Input: CBitSetType& other - BitSet to copy Output: *this \*****************************************************************************/ template CBitSetType& CBitSetType::operator= ( const CBitSetType &other ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); Copy( other ); RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return *this; } /*****************************************************************************\ Function: CBitSet::operator |= Description: Computes the union of this bitset with another bitset. Input: CBitSetType& other - other BitSet Output: *this \*****************************************************************************/ template CBitSetType& CBitSetType::operator|= ( const CBitSetType &other ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); DWORD size = other.m_Size; if( m_Size < other.m_Size ) { Create( other.m_Size ); size = m_Size; } ASSERT( m_Size >= other.m_Size ); if( StoredInPtr() ) { ASSERT( other.StoredInPtr() ); m_PtrBits |= other.m_PtrBits; } else { const BITSET_ARRAY_TYPE* pOtherArray = other.GetArrayPointer(); DWORD index = ( size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; while( index-- ) { m_BitSetArray[ index ] |= pOtherArray[ index ]; } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return *this; } /*****************************************************************************\ Function: CBitSet::operator &= Description: Computes the intersection of this bitset with another bitset. Input: CBitSetType& other - other BitSet Output: *this \*****************************************************************************/ template CBitSetType& CBitSetType::operator&= ( const CBitSetType &other ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); DWORD size = other.m_Size; if( m_Size < other.m_Size ) { Create( other.m_Size ); size = m_Size; } ASSERT( m_Size >= other.m_Size ); if( StoredInPtr() ) { ASSERT( other.StoredInPtr() ); m_PtrBits &= other.m_PtrBits; } else { const BITSET_ARRAY_TYPE* pOtherArray = other.GetArrayPointer(); DWORD index = ( size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; while( index-- ) { m_BitSetArray[ index ] &= pOtherArray[ index ]; } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return *this; } /*****************************************************************************\ Function: CBitSet::Create Description: Creates the internal BitSet structure of the specified size Input: DWORD size - number of elements Output: void \*****************************************************************************/ template void CBitSetType::Create( DWORD size ) { if( size == m_Size ) { // Nothing to do... } if( size <= cBitsInPtr ) { // Bitset will fit in pointer. bitptr_t newPtrBits = this->ConvertTo(); Delete(); m_Size = size; m_PtrBits = newPtrBits & GetActivePtrMask(); } else { BITSET_ARRAY_TYPE* ptrThis = GetArrayPointer(); const DWORD cNewArraySize = ( size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; const DWORD cOldArraySize = ( m_Size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; const BITSET_ARRAY_TYPE cExtraBits = size % cBitsPerArrayElement; const BITSET_ARRAY_TYPE cExtraBitMask = cExtraBits ? ( ( 1 << cExtraBits ) - 1 ) : ( ~0 ); if( cNewArraySize == cOldArraySize ) { m_Size = size; if( cNewArraySize ) { ptrThis[ cNewArraySize - 1 ] &= cExtraBitMask; } } else if( cNewArraySize ) { BITSET_ARRAY_TYPE* ptr = (BITSET_ARRAY_TYPE*) CAllocatorType::Allocate( sizeof(BITSET_ARRAY_TYPE) * cNewArraySize ); if( ptr ) { if( ptrThis ) { if( cNewArraySize > cOldArraySize ) { MemCopy( ptr, ptrThis, cOldArraySize * sizeof(ptrThis[0]) ); SafeMemSet( ptr + cOldArraySize, 0, ( cNewArraySize - cOldArraySize) * sizeof(ptrThis[0]) ); } else { MemCopy( ptr, ptrThis, cNewArraySize * sizeof(ptrThis[0]) ); if( cNewArraySize ) { ptr[ cNewArraySize - 1 ] &= cExtraBitMask; } } } else { SafeMemSet( ptr, 0, cNewArraySize * sizeof(ptrThis[0]) ); } Delete(); m_BitSetArray = ptr; m_Size = size; } else { ASSERT( 0 ); } } else { Delete(); } } } /*****************************************************************************\ Function: CBitSet::Copy Description: Copies information from one bitset to this bitset. Input: const CBitSetType& other - bitset to copy. Output: void \*****************************************************************************/ template void CBitSetType::Copy( const CBitSetType& other ) { if( this != &other ) { if( m_Size != other.m_Size ) { Create( other.m_Size ); } if( m_Size == other.m_Size ) { ASSERT( this->StoredInPtr() == other.StoredInPtr() ); if( StoredInPtr() ) { m_PtrBits = other.m_PtrBits; } else { const DWORD cArraySizeInBytes = ( other.m_Size + BITS_PER_BYTE - 1 ) / BITS_PER_BYTE; MemCopy( m_BitSetArray, other.m_BitSetArray, cArraySizeInBytes ); } } else { // Should not happen - indicates failed memory allocation. ASSERT( 0 ); } } } /*****************************************************************************\ Function: CBitSet::Delete Description: Deletes the internal BitSet structure Input: void Output: void \*****************************************************************************/ template void CBitSetType::Delete( void ) { ASSERT( m_BitSetArray || StoredInPtr() ); if( !StoredInPtr() && m_BitSetArray ) { CAllocatorType::Deallocate( m_BitSetArray ); } m_BitSetArray = NULL; m_Size = 0; } /*****************************************************************************\ Function: CBitSet::BitCount Description: Counts number of bits set in BitSet Input: void Output: DWORD number of bits set in BitSet \*****************************************************************************/ template DWORD CBitSetType::BitCount( void ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); DWORD bitCount = 0; if( StoredInPtr() ) { bitCount = CPtrSize::Count( m_PtrBits ); } else { const DWORD cBitsPerArrayElement = ( sizeof(m_BitSetArray[0]) * 8 ); DWORD index = ( m_Size + cBitsPerArrayElement - 1 ) / cBitsPerArrayElement; while( index-- ) { BITSET_ARRAY_TYPE Elem = m_BitSetArray[index]; bitCount += iSTD::BitCount( Elem ); } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return bitCount; } /*****************************************************************************\ Function: CBitSet::BitCount Description: Counts number of bits set in BitSet up to (and including) limit-th index Input: DWORD index Output: DWORD number of bits set in BitSet up to (and including) limit-th index \*****************************************************************************/ template DWORD CBitSetType::BitCount( DWORD limit ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); DWORD bitCount = 0; limit = iSTD::Min( limit, m_Size-1 ); for( DWORD i=0; i <= limit; i++ ) { if( IsSet( i ) ) { bitCount++; } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return bitCount; } /*****************************************************************************\ Function: CBitSet::StoredInPtr Description: True if bits are stored in pointer. Input: Output: bool \*****************************************************************************/ template bool CBitSetType::StoredInPtr( void ) const { return m_Size <= cBitsInPtr; } /*****************************************************************************\ Function: CBitSet::GetActivePtrMask Description: Returns pointer mask depending on set size. Can only be called if bits are stored in pointer. Input: Output: bitptr_t - active mask \*****************************************************************************/ template typename CBitSetType::bitptr_t CBitSetType::GetActivePtrMask( void ) const { ASSERT( StoredInPtr() ); if( m_Size == cBitsInPtr ) { return static_cast( -1 ); } return CPtrSize::Bit( m_Size ) - 1; } /*****************************************************************************\ Function: CBitSet::GetArrayPointer Description: Return pointer to bitset array. If bits are stored in pointer itself, return pointer to this pointer. Input: Output: BITSET_ARRAY_TYPE* \*****************************************************************************/ template typename CBitSetType::BITSET_ARRAY_TYPE* CBitSetType::GetArrayPointer( void ) { if( StoredInPtr() ) { return ( reinterpret_cast( &m_PtrBits ) ); } else { return m_BitSetArray; } } /*****************************************************************************\ Function: CBitSet::GetArrayPointer Description: Return pointer to bitset array. If bits are stored in pointer itself, return pointer to this pointer. Input: Output: const BITSET_ARRAY_TYPE* \*****************************************************************************/ template const typename CBitSetType::BITSET_ARRAY_TYPE* CBitSetType::GetArrayPointer( void ) const { if( StoredInPtr() ) { return ( reinterpret_cast( &m_PtrBits ) ); } else { return m_BitSetArray; } } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Buffer.h000066400000000000000000000126761363533017100237630ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "LinearAllocator.h" #include "MemCopy.h" namespace iSTD { /*****************************************************************************\ Class: CBuffer Description: Allocates and manages a system memory buffer \*****************************************************************************/ template class CBuffer : public CLinearAllocator { public: CBuffer( void ); virtual ~CBuffer( void ); bool Allocate( const DWORD allocSize, const DWORD alignSize ); void Deallocate( void ); DWORD GetBlockSize( void ) const; void* GetLinearAddress( void ) const; protected: BYTE* m_pAllocAddress; // Address of allocation pointer }; /*****************************************************************************\ Function: CBuffer Constructor Description: Initializes internal data Input: none Output: none \*****************************************************************************/ template inline CBuffer::CBuffer( void ) : CLinearAllocator( NULL, 0 ) { m_pAllocAddress = NULL; } /*****************************************************************************\ Function: CBuffer Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template inline CBuffer::~CBuffer( void ) { Deallocate(); } /*****************************************************************************\ Function: CBuffer::Allocate Description: Allocates memory for the buffer Input: const DWORD allocSize - size in bytes const DWORD alignSize - alignment in bytes Output: bool - success or fail \*****************************************************************************/ template inline bool CBuffer::Allocate( const DWORD allocSize, const DWORD alignSize ) { Deallocate(); const DWORD alignedAllocSize = allocSize + alignSize; if( alignedAllocSize ) { m_pAllocAddress = (BYTE*)CAllocatorType::Allocate( alignedAllocSize ); if( m_pAllocAddress ) { const DWORD offset = ( alignSize ) ? GetAlignmentOffset( m_pAllocAddress, alignSize ) : 0; this->m_pBaseAddress = this->m_pAllocAddress + offset; this->m_Size = allocSize; SafeMemSet( this->m_pBaseAddress, 0, this->m_Size ); } else { ASSERT(0); this->m_Size = 0; } } else { ASSERT(0); this->m_Size = 0; } this->m_SizeUsed = 0; this->m_SizeReserved = 0; return ( this->m_Size ) ? true : false; } /*****************************************************************************\ Function: CBuffer::Deallocate Description: Deallocates memory for the buffer Input: none Output: none \*****************************************************************************/ template inline void CBuffer::Deallocate( void ) { CAllocatorType::Deallocate( m_pAllocAddress ); m_pAllocAddress = NULL; this->m_pBaseAddress = NULL; this->m_Size = 0; this->m_SizeUsed = 0; this->m_SizeReserved = 0; } /*****************************************************************************\ Function: CBuffer::GetBlockSize Description: Gets the total size of the buffer Input: none Output: DWORD - size in bytes \*****************************************************************************/ template inline DWORD CBuffer::GetBlockSize( void ) const { return this->m_Size; } /*****************************************************************************\ Function: CBuffer::GetLinearAddress Description: Gets the base address of the buffer Input: void Output: void* - linear address \*****************************************************************************/ template inline void* CBuffer::GetLinearAddress( void ) const { return (void*)(this->m_pBaseAddress); } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/CpuUtil.h000066400000000000000000000062031363533017100241240ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "types.h" #include "utility.h" #include "UFO/portable_cpuid.h" namespace iSTD { /*****************************************************************************\ ENUM: CPU_INSTRUCTION_LEVEL \*****************************************************************************/ enum CPU_INSTRUCTION_LEVEL { CPU_INSTRUCTION_LEVEL_UNKNOWN, CPU_INSTRUCTION_LEVEL_MMX, CPU_INSTRUCTION_LEVEL_SSE, CPU_INSTRUCTION_LEVEL_SSE2, CPU_INSTRUCTION_LEVEL_SSE3, CPU_INSTRUCTION_LEVEL_SSE4, CPU_INSTRUCTION_LEVEL_SSE4_1, NUM_CPU_INSTRUCTION_LEVELS }; /*****************************************************************************\ Inline Function: GetCpuInstructionLevel Description: Returns the highest level of IA32 intruction extensions supported by the CPU ( i.e. SSE, SSE2, SSE4, etc ) Output: CPU_INSTRUCTION_LEVEL - highest level of IA32 instruction extension(s) supported by CPU Notes: See Table 3-20 Vol2A SW Dev Manual for bit-field numbering \*****************************************************************************/ inline CPU_INSTRUCTION_LEVEL GetCpuInstructionLevel( void ) { #if defined(ANDROID) && defined(__SSE4_1__) return CPU_INSTRUCTION_LEVEL_SSE4_1; #else int CPUInfo[4] = { 0, 0, 0, 0 }; __cpuid(CPUInfo, 1); CPU_INSTRUCTION_LEVEL CpuInstructionLevel = CPU_INSTRUCTION_LEVEL_UNKNOWN; if( CPUInfo[2] & BIT(19) ) { CpuInstructionLevel = CPU_INSTRUCTION_LEVEL_SSE4_1; } else if( CPUInfo[2] & BIT(0) ) { CpuInstructionLevel = CPU_INSTRUCTION_LEVEL_SSE3; } else if( CPUInfo[3] & BIT(26) ) { CpuInstructionLevel = CPU_INSTRUCTION_LEVEL_SSE2; } else if( CPUInfo[3] & BIT(25) ) { CpuInstructionLevel = CPU_INSTRUCTION_LEVEL_SSE; } else if( CPUInfo[3] & BIT(23) ) { CpuInstructionLevel = CPU_INSTRUCTION_LEVEL_MMX; } return CpuInstructionLevel; #endif } }//namespace iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Debug.h000066400000000000000000000051421363533017100235660ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #ifdef __cplusplus /*****************************************************************************\ MACRO: ASSERT \*****************************************************************************/ #ifndef ASSERT #define ASSERT( expr ) #endif /*****************************************************************************\ MACRO: DPF PURPOSE: Debug Print function \*****************************************************************************/ #ifndef DPF #define DPF( debugLevel, message, ...) #endif /*****************************************************************************\ MACRO: GFXDBG_STDLIB PURPOSE: Special Debug Print flag for iSTD classes \*****************************************************************************/ #define GFXDBG_STDLIB (0x00001000) /*****************************************************************************\ MACRO: NODEFAULT PURPOSE: The use of __assume(0) tells the optimizer that the default case cannot be reached. As a result, the compiler does not generate code to test whether p has a value not represented in a case statement. Note that __assume(0) must be the first statement in the body of the default case for this to work. \*****************************************************************************/ #ifndef NODEFAULT #ifdef _MSC_VER #define NODEFAULT __assume(0) #else #define NODEFAULT #endif // _MSC_VER #endif // NODEFAULT #endif // __cplusplus intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/DisjointSet.h000066400000000000000000000167131363533017100250050ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #include "Queue.h" namespace iSTD { /*****************************************************************************\ Struct: IsDisjointSetTypeSupported \*****************************************************************************/ template struct IsDisjointSetTypeSupported { enum { value = false }; }; template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; #ifndef __LP64__ // u/long on linux64 platform is 64-bit type and collides with U/INT64 template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; #endif template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; template<> struct IsDisjointSetTypeSupported { enum { value = true }; }; template struct IsDisjointSetTypeSupported { enum { value = true }; }; /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define DisjointSetTemplateList class Type, class CAllocatorType #define CDisjointSetType CDisjointSet /*****************************************************************************\ Class: CDisjointSet Description: Implements a union find disjoint set \*****************************************************************************/ template class CDisjointSet : public CObject { public: CDisjointSet( void ); virtual ~CDisjointSet( void ); void Union( CDisjointSetType& ds ); const Type& Find( void ); void Set( const Type& item ); C_ASSERT( IsDisjointSetTypeSupported::value == true ); protected: CDisjointSetType* RootRecursive( CDisjointSetType* node ); CDisjointSetType* RootNonRecursive( CDisjointSetType* node ); CDisjointSetType* m_pParent; Type m_Item; }; /*****************************************************************************\ Function: CDisjointSet Constructor Description: Initializes the disjoint set Input: Output: none \*****************************************************************************/ template CDisjointSetType::CDisjointSet( void ) : CObject() { m_pParent = this; } /*****************************************************************************\ Function: CDisjointSet Destructor Description: Frees all internal dynamic memory Input: none Output: none \*****************************************************************************/ template CDisjointSetType::~CDisjointSet( void ) { // Nothing! } /*****************************************************************************\ Function: CDisjointSet::Union Description: Unions this disjoint set with the passed in disjoint set Input: CDisjointSet& ds - other disjoint set Output: void \*****************************************************************************/ template void CDisjointSetType::Union( CDisjointSetType& ds ) { CDisjointSetType* oldRoot = RootNonRecursive( this ); CDisjointSetType* newRoot = RootNonRecursive( &ds ); if( oldRoot != newRoot ) { oldRoot->m_pParent = newRoot; } } /*****************************************************************************\ Function: CDisjointSet::Find Description: Finds the item in this disjoint set Input: void Output: const Type& - root of this disjoint set \*****************************************************************************/ template const Type& CDisjointSetType::Find( void ) { CDisjointSetType* root = RootNonRecursive( this ); return root->m_Item; } /*****************************************************************************\ Function: CDisjointSet::Set Description: Sets the item stored in this disjoint set Input: const Type& - item stored in this disjoint set Output: void \*****************************************************************************/ template void CDisjointSetType::Set( const Type& item ) { CDisjointSetType* root = RootNonRecursive( this ); root->m_Item = item; } /*****************************************************************************\ Function: CDisjointSet::RootRecursive Description: Returns the root node of this disjoint set. Also performs path compression using recursion. Input: void Output: CDisjointSetType* root node \*****************************************************************************/ template CDisjointSetType* CDisjointSetType::RootRecursive( CDisjointSetType* node ) { if( node->m_pParent != node ) { CDisjointSetType* root = RootRecursive( node->m_pParent ); node->m_pParent = root; } return node; } /*****************************************************************************\ Function: CDisjointSet::RootNonRecursive Description: Returns the root node of this disjoint set. Also performs path compression without using recursion. The actual path compression isn't quite as good as the recursive version but it's pretty good and the speed gains from not using recursion might be more important. Input: void Output: CDisjointSetType* root node \*****************************************************************************/ template CDisjointSetType* CDisjointSetType::RootNonRecursive( CDisjointSetType* node ) { while( node->m_pParent != node ) { node->m_pParent = node->m_pParent->m_pParent; node = node->m_pParent; } return node; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/FastMask.h000066400000000000000000000410311363533017100242460ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #ifndef ASSERT #include "..\..\d3d\ibdw\d3ddebug.h" #endif namespace iSTD { /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define FastMaskTemplateList bool OrderedList #define CFastMaskSetType CFastMask /*****************************************************************************\ Class: FastMask Description: Simple ordered mask with minimal set list traversal \*****************************************************************************/ template class CFastMask { public: CFastMask( unsigned int inSize ); virtual ~CFastMask(); inline bool IsValid( void ) const; inline bool IsSet( unsigned int index ) const; inline bool IsDirty ( void ); inline const unsigned int* GetMask(unsigned int &ioSetKey); inline unsigned int GetSize(); inline unsigned int GetSetListSize(); inline void GetUnsortedSetList( unsigned int const** ioList, unsigned int &ioSize ); inline void GetSetList( unsigned int const** ioList, unsigned int &ioSize ); inline void SetBits( unsigned int index, unsigned int count ); inline void SetBit( unsigned int index ); inline void ClearBits( void ); inline void UnSetBit( unsigned int index ); inline void Resize ( unsigned int in_NewSize ); protected: inline void SortSetList( void ); inline void CollapseSetList( void ); unsigned int* m_Mask; unsigned int* m_SetList; unsigned int m_Key; unsigned int m_SortIdx; unsigned int m_CollapseIdx; unsigned int m_SetListSize; unsigned int m_Capacity; bool m_SortOnGet; bool m_CollapseUnsorted; }; /*****************************************************************************\ Function: Constructor Description: Constructs a mask with the incoming size \*****************************************************************************/ template CFastMaskSetType::CFastMask( unsigned int inSize ) : m_Mask(0) , m_SetList(0) , m_Key(1) , m_SortIdx(0) , m_CollapseIdx(0) , m_SetListSize(0) , m_Capacity(inSize) , m_SortOnGet(false) , m_CollapseUnsorted(false) { ASSERT(inSize > 0); if( inSize > 0 ) { m_Mask = new unsigned int[m_Capacity]; m_SetList = new unsigned int[m_Capacity]; ASSERT(0 != m_Mask); ASSERT(0 != m_SetList); if( m_Mask && m_SetList ) { // quick run up to next power of 2 while( (unsigned int)m_Key <= m_Capacity ) { m_Key = m_Key << 1; } // clear mask for( unsigned int i = 0; i < m_Capacity; i++ ) { m_Mask[i] = m_Key; } } else { SafeDeleteArray( m_Mask ); SafeDeleteArray( m_SetList ); } } } /*****************************************************************************\ Function: Destructor Description: Cleanup memory \*****************************************************************************/ template CFastMaskSetType::~CFastMask( void ) { SafeDeleteArray(m_Mask); SafeDeleteArray(m_SetList); } /*****************************************************************************\ Function: IsValid Description: Returns whether the object has been constructed properly. \*****************************************************************************/ template bool CFastMaskSetType::IsValid( void ) const { return ( ( m_Mask != NULL ) && ( m_SetList != NULL ) ); } /*****************************************************************************\ Function: IsSet Description: Returns whether or not a bit has been set in the mask. \*****************************************************************************/ template bool CFastMaskSetType::IsSet( unsigned int index ) const { ASSERT( index < m_Capacity ); return ( m_Key != m_Mask[index] ); } /*****************************************************************************\ Function: IsDirty Description: Returns whether or not the mask is dirty \*****************************************************************************/ template bool CFastMaskSetType::IsDirty( void ) { if( true == m_CollapseUnsorted ) { CollapseSetList(); } return (m_SetListSize > 0); } /*****************************************************************************\ Function: GetMask Description: Get the current mask with the set key for use in optimal comparisons for multiple bits. \*****************************************************************************/ template const unsigned int* CFastMaskSetType::GetMask( unsigned int &ioSetKey ) { ioSetKey = m_Key; return m_Mask; } /*****************************************************************************\ Function: GetSize Description: Returns the number of possible indices. \*****************************************************************************/ template unsigned int CFastMaskSetType::GetSize( void ) { return m_Capacity; } /*****************************************************************************\ Function: GetSetListSize Description: Returns the number set indices \*****************************************************************************/ template unsigned int CFastMaskSetType::GetSetListSize( void ) { if( true == m_CollapseUnsorted ) { CollapseSetList(); } return m_SetListSize; } /*****************************************************************************\ Function: SetBits Description: Sets mask bits from index to count. \*****************************************************************************/ template void CFastMaskSetType::SetBits( unsigned int index, unsigned int count ) { ASSERT( (index + count) <= m_Capacity ); for( unsigned int i = index; i < index + count; i++ ) { if( m_Key == m_Mask[i] ) { // when the user sets/un-sets bits often without a Get* then there // exists a possibility of overrunning the setlist. if( m_SetListSize >= m_Capacity ) { CollapseSetList(); } ASSERT(m_SetListSize < m_Capacity); m_Mask[i] = m_SetListSize; m_SetList[m_SetListSize++] = i; if( OrderedList ) { m_SortOnGet = true; } } } } /*****************************************************************************\ Function: SetBit Description: Sets mask bit for index \*****************************************************************************/ template void CFastMaskSetType::SetBit( unsigned int index ) { ASSERT( index < m_Capacity ); if( m_Key == m_Mask[index] ) { if( m_SetListSize >= m_Capacity ) { CollapseSetList(); } ASSERT(m_SetListSize < m_Capacity); m_Mask[index] = m_SetListSize; m_SetList[m_SetListSize++] = index; if( OrderedList ) { m_SortOnGet = true; } } } /*****************************************************************************\ Function: GetUnsortedSetList Description: Gets an unsorted set list as an override if the list is sorted but you don't require sorting at this point. \*****************************************************************************/ template void CFastMaskSetType::GetUnsortedSetList( unsigned int const** ioList, unsigned int &ioSize ) { if( true == m_CollapseUnsorted ) { CollapseSetList(); } *ioList = m_SetList; ioSize = m_SetListSize; } /*****************************************************************************\ Function: GetSetList Description: Gets the set list for traversal \*****************************************************************************/ template void CFastMaskSetType::GetSetList( unsigned int const** ioList, unsigned int &ioSize ) { if( OrderedList && ( true == m_SortOnGet ) ) { SortSetList(); } else if( true == m_CollapseUnsorted ) { CollapseSetList(); } *ioList = m_SetList; ioSize = m_SetListSize; } /*****************************************************************************\ Function: ClearBits Description: Remove the bit from the list and mask if necessary \*****************************************************************************/ template void CFastMaskSetType::ClearBits( void ) { unsigned int index = 0; // walk the set list and remove set elements for( unsigned int i = 0; i < m_SetListSize; i++ ) { index = m_SetList[i]; // the user can un-set bits prior to calling clear and we need to ensure // that we dont try to change those entries as they dont matter and could // corrupt the heap if( index != m_Key ) { m_Mask[index] = m_Key; } } m_SetListSize = 0; m_SortIdx = 0; m_CollapseIdx = 0; m_SortOnGet = false; m_CollapseUnsorted = false; } /*****************************************************************************\ Function: UnSetBit Description: Remove the bit from the list and mask if necessary \*****************************************************************************/ template void CFastMaskSetType::UnSetBit( unsigned int index ) { ASSERT( index < m_Capacity ); // we do not change the setlist size because we will rely // upon the sort to remove those key elements if( m_Key != m_Mask[index] ) { // set that we need to collapse this list, required if we query an // unsorted set from a sorted set list m_CollapseUnsorted = true; unsigned int setListPos = m_Mask[index]; if( setListPos < m_CollapseIdx ) { m_CollapseIdx = setListPos; // we need to start our collapse at this index } // handle ordered list if( OrderedList ) { // if we are an ordered list we need to compare the index position // with the current sort index and modify that index if necessary if( setListPos < m_SortIdx ) { m_SortIdx = setListPos; // move index down to allow for collapse } m_SortOnGet = true; } m_SetList[m_Mask[index]] = m_Key; m_Mask[index] = m_Key; } } /*****************************************************************************\ Function: Resize Description: Resizes the FastMask. \*****************************************************************************/ template void CFastMaskSetType::Resize( unsigned int in_NewSize ) { ASSERT(in_NewSize != 0); if( in_NewSize == m_Capacity ) return; unsigned int* old_m_SetList = m_SetList; unsigned int old_m_SetListSize = m_SetListSize; m_SetListSize = 0; //will be using SetBits() which will correct this value m_CollapseIdx = 0; m_SortIdx = 0; m_Capacity = in_NewSize; m_CollapseUnsorted = false; m_SortOnGet = false; SafeDeleteArray(m_Mask); m_Mask = new unsigned int[m_Capacity]; m_SetList = new unsigned int[m_Capacity]; ASSERT(0 != m_Mask); ASSERT(0 != m_SetList); // save off old key unsigned int old_m_Key = m_Key; m_Key = 1; // quick run up to next power of 2 while( (unsigned int)m_Key <= m_Capacity ) { m_Key = m_Key << 1; } for( unsigned int i = 0; i < m_Capacity; i++) { m_Mask[i] = m_Key; } for( unsigned int i = 0; i < old_m_SetListSize; i++) { if(old_m_SetList[i] != old_m_Key) { SetBit(old_m_SetList[i]); } } SafeDeleteArray(old_m_SetList); } /*****************************************************************************\ Function: SortSetList Description: Sorts the set list, a modified insertion sort algorithm http://en.wikipedia.org/wiki/Insertion_sort \*****************************************************************************/ template void CFastMaskSetType::SortSetList( ) { // perform an insertion sort in place unsigned int count = 0; unsigned int keyVal = 0; int idx; for( unsigned int i = m_SortIdx; i < m_SetListSize; i++ ) { keyVal = m_SetList[i]; // handle un-set bit if( keyVal == m_Key ) { count++; // increment number of un-set keys seen, these will // automatically be sorted to the RHS of the list } idx = i - 1; // find the sort position for this keyVal while( idx >= 0 && m_SetList[idx] > keyVal ) { m_SetList[idx+1] = m_SetList[idx]; idx--; } m_SetList[idx+1] = keyVal; } m_SetListSize -= count; // subtract off the number of un-set bits on the RHS m_SortOnGet = false; m_CollapseUnsorted = false; m_SortIdx = ( m_SetListSize > 0 ) ? m_SetListSize - 1 : 0; m_CollapseIdx = m_SortIdx; // update the mask with the new positions for( unsigned int i = 0; i < m_SetListSize; i++ ) { m_Mask[m_SetList[i]] = i; // new index } } /*****************************************************************************\ Function: CollapseSetList Description: Removes any un-set bits from the set list \*****************************************************************************/ template void CFastMaskSetType::CollapseSetList( ) { // walk the set list and collapse by skipping over un-set elements unsigned int count = m_CollapseIdx; for( unsigned int i = m_CollapseIdx; i < m_SetListSize; i++ ) { if( m_Key != m_SetList[i] ) { m_Mask[m_SetList[i]] = count; // update mask with new position m_SetList[count++] = m_SetList[i]; } } m_CollapseUnsorted = false; m_SetListSize = count; if( 0 == m_SetListSize ) { m_SortIdx = 0; m_CollapseIdx = 0; if( OrderedList ) { m_SortOnGet = false; // no need to sort if empty } } else { if( m_CollapseIdx < m_SortIdx ) { m_SortIdx = m_CollapseIdx; if( OrderedList ) { m_SortOnGet = true; } } m_CollapseIdx = m_SetListSize - 1; } } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/File.h000066400000000000000000000476601363533017100234320ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #include #include #include #include "MemCopy.h" #include "Debug.h" #if defined _WIN32 # include # include # include # include // disable warning about deprecated functions: // 'vsprintf' and 'fopen' # pragma warning(push) # pragma warning(disable: 4996) #elif defined(__GNUC__) # include # include #endif namespace iSTD { /*****************************************************************************\ Function Prototypes \*****************************************************************************/ inline int DirectoryCreate( const char * dirPath ); inline DWORD GetModuleFileName( char* pFileName, DWORD bufSize ); inline void* FileOpen( const char * fileName, const char * mode ); inline void FileWrite( const void* pFile, const char * str, ... ); inline void FileClose( void* pFile ); inline DWORD FileRead( const void* pFile, void* pBuffer, DWORD bufSize ); inline DWORD FileSize( const void* pFile ); inline void LogToFile( const char* filename, const char * str, ... ); inline signed long ReadParamFromFile( char* filename, DWORD line ); /*****************************************************************************\ Inline Function: DirectoryCreate Description: Creates a directory \*****************************************************************************/ inline int DirectoryCreate( const char * dirPath ) { #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) # if defined _WIN32 return _mkdir( dirPath ); # endif # if defined (__GNUC__) return mkdir( dirPath, ( S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_IFDIR ) ); # endif #endif } /*****************************************************************************\ Inline Function: GetModuleFileName Description: Gets file name of a runnimg application module \*****************************************************************************/ inline DWORD GetModuleFileName( char* pFileName, DWORD bufSize ) { #if defined(ISTDLIB_KMD) // TO DO: Currently not implemented for kernel-mode return 0; #elif defined(ISTDLIB_UMD) #if defined(_WIN32) return ::GetModuleFileNameA( NULL, pFileName, bufSize ); #elif defined(__linux__) //TODO: add Linux implementation. return 0; #else // TO DO: replace with non-Windows version #error "TODO implement non-Windows equivalent of GetModuleFileName" #endif #else // this compilation path is not intended // neither UMD nor KMD flag is set // this assert is commented out due to the number of solutions that do not define // ISTDLIB as KMD or UMD, it may be enabled in separate commit // C_ASSERT( 0 ); return 0; #endif } /*****************************************************************************\ Inline Function: OpenFile Description: Opens a file based on the provided mode \*****************************************************************************/ inline void* FileOpen( const char * fileName, const char * mode ) { FILE * pFile; #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented pFile = NULL; #elif defined(ISTDLIB_UMD) pFile = fopen( fileName , mode ); #if defined(_WIN32) // Clear extra error information = ERROR_ALREADY_EXISTS set by windows when function success // It is necessary, cause it could be wrongly interpreted as fail of other function. if ( pFile && GetLastError() == ERROR_ALREADY_EXISTS ) { SetLastError( 0 ); } #endif #endif return pFile; } /*****************************************************************************\ Inline Function: CloseFile Description: Close a file \*****************************************************************************/ inline void FileClose( void* pFile ) { #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) if( pFile ) { fclose ( (FILE*)pFile ); } #endif } /*****************************************************************************\ Inline Function: WriteFile Description: Writes the str to the provide file if it exists \*****************************************************************************/ inline void FileWrite( const void* pFile, const char * str, ... ) { #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) if( str != NULL ) { va_list args; va_start( args, str ); const size_t length = _vscprintf( str, args ); va_end( args ); char* temp = new char[ length + 1 ]; if( temp ) { va_start( args, str ); VSNPRINTF( temp, length + 1, length+ 1, str, args ); va_end( args ); if( pFile ) { fwrite( temp , 1 , length, (FILE*)pFile ); } delete[] temp; } } #endif } /*****************************************************************************\ Inline Function: WriteFile Description: Overloaded function writes stream to the provide file if it exists \*****************************************************************************/ inline void FileWrite( const void * str, size_t size , size_t count, const void* pFile ) { #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) if( str != NULL ) { if( pFile ) { fwrite( str , size , count , (FILE*)pFile ); } } #endif } /*****************************************************************************\ Inline Function: FileRead Description: Reads bufSize bytes from given file, and saves it to pBuffer. Returns number of read bytes - it may be diffrent than bufSize, if file is shorter than bufSize. \*****************************************************************************/ inline DWORD FileRead( const void* pFile, void* pBuffer, DWORD bufSize ) { DWORD bytesRead = 0; #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) if( pFile ) { bytesRead = (DWORD) fread( pBuffer, sizeof(BYTE), bufSize, (FILE*)pFile ); } #endif return bytesRead; } /*****************************************************************************\ Inline Function: FileSize Description: Returns size in bytes of given file. \*****************************************************************************/ inline DWORD FileSize( const void* pFile ) { DWORD fileSize = 0; #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) if( pFile ) { long int currPosition = ftell( (FILE*)pFile ); fseek( (FILE*)pFile, 0, SEEK_END ); // Clamp result to 0, ftell can return -1 in case of an error. long int endPosition = ftell( (FILE*)pFile ); fileSize = (DWORD)( endPosition >= 0 ? endPosition : 0 ); fseek( (FILE*)pFile, currPosition, SEEK_SET ); } #endif return fileSize; } /*****************************************************************************\ Inline Function: LogToFile Description: Writes the str to the file with provided filename, creates the file if it does not exists, for debug purposes only \*****************************************************************************/ inline void LogToFile( const char* filename, const char * str, ... ) { #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) if( str != NULL ) { va_list args; va_start( args, str ); const size_t length = _vscprintf( str, args ); va_end( args ); char* temp = new char[ length + 1 ]; if( temp ) { va_start( args, str ); VSNPRINTF( temp, length + 1, length + 1, str, args ); va_end( args ); FILE* file = fopen( filename, "a" ); if( file ) { fwrite( temp , 1 , length, (FILE*)file ); fclose( file ); } delete[] temp; } } #endif } /*****************************************************************************\ Inline Function: ReadParamFromFile Description: reads n-th line from file specified as param, converts it (if possible) to signed long and return its value, if conversion is impossible or if file does not exists returns 0, line length in file cannot exceed bufsize (currently 20) characters, for debug purposes only \*****************************************************************************/ inline signed long ReadParamFromFile( char* filename, DWORD line = 1 ) { signed long ret = 0; #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) FILE* file = fopen( filename, "r" ); if( file ) { const char bufsize = 20; char buf[ bufsize + 1 ] = ""; // skip first n-1 lines while( --line && !feof( file ) ) { fgets( buf, bufsize, file ); } if( !feof( file ) ) { iSTD::SafeMemSet( buf, 0, bufsize ); fgets( buf, bufsize, file ); ret = atoi( buf ); } fclose( file ); } #endif return ret; } /*****************************************************************************\ Inline Function: CreateAppOutputDir Description: Creates folder path based on outputDirectory string and input parameters. Then writes it in pathBuf. Input: unsigned int bufSize const char* outputDirectory bool addSystemDrive bool addProcName bool pidEnabled Output: char* pathBuf int ret - return value: 0 - success, -1 - fail \*****************************************************************************/ inline int CreateAppOutputDir( char* pathBuf, unsigned int bufSize, const char* outputDirectory, bool addSystemDrive, bool addProcName, bool pidEnabled ) { int ret = 0; #if defined(ISTDLIB_KMD) // TO DO: Currently only UMD is implemented #elif defined(ISTDLIB_UMD) && defined(_WIN32) const size_t size = 1024; char outputDirPath[size] = {0}; if( addSystemDrive ) { // get system drive from environment variables char* envSystemDrive = getenv( "SystemDrive" ); if( envSystemDrive ) { STRCPY( outputDirPath, size, envSystemDrive ); } STRCAT( outputDirPath, size, outputDirectory ); } else { STRCPY( outputDirPath, size, outputDirectory ); } //check whether latest mark is backslash and insert it if not size_t pathLen = strnlen_s( outputDirPath, size ); if( ( pathLen < size ) && ( outputDirPath[pathLen-1] != '\\' ) ) { STRCAT( outputDirPath, size, "\\" ); } if( addProcName ) { char appPath[512] = {0}; // check a process id and make an adequate directory for it: if( GetModuleFileName( appPath, sizeof(appPath) -1 ) ) { char* pprocessName = strrchr( appPath, '\\' ); STRCAT( outputDirPath, size, ++pprocessName ); STRCAT( outputDirPath, size, "\\" ); } else { STRCAT( outputDirPath, size, "unknownProcess\\" ); } if ( pidEnabled ) { //append process id size_t pid = _getpid(); size_t pathLen = strnlen_s( outputDirPath, size ); if( ( pathLen < size ) && ( pathLen > 0 ) ) { //check latest mark and add pid number before backslash if( outputDirPath[pathLen-1] == '\\' ) { --pathLen; } SPRINTF( outputDirPath + pathLen, size - pathLen, "_%Id\\", pid ); } } } char currDirectory[size] = {0}; int currDirIter = 0; const char* cPtr = outputDirPath; bool afterFirstSlash = false; errno_t err; // Create directories in path one by one while( *cPtr ) { currDirectory[currDirIter++] = *cPtr; currDirectory[currDirIter] = 0; // If we found backslash, create directory. // Omit first backslash - this is the root if( *cPtr == '\\' ) { if( afterFirstSlash ) { if( DirectoryCreate( currDirectory ) != 0 ) { _get_errno( &err ); if ( err != EEXIST ) { ret = -1; break; } } } else { afterFirstSlash = true; } } cPtr++; } DWORD length = ( DWORD ) strlen( outputDirPath ); length = ( bufSize-1 < length ) ? bufSize-1 : length; MemCopy( pathBuf, outputDirPath, length ); pathBuf[length] = 0; #elif !defined(_WIN32) //if not Win, need to be Linux or Android. //not _WIN32 is needed because not all projects define ISTDLIB_UMD char *path = (char*)malloc(sizeof(char)*bufSize); char *outputDirectoryCopy = (char*)malloc(sizeof(char)*bufSize); if (NULL == path) { return -1; } STRCPY(outputDirectoryCopy, bufSize, outputDirectory); if (addProcName) { const int defaultBuffSize = 1024; //max size for file from /proc/%d/cmdline char cmdpath[defaultBuffSize]; char cmdline[defaultBuffSize] = "\0"; unsigned int pid = getpid(); snprintf(cmdpath, defaultBuffSize - 1, "/proc/%u/cmdline", pid); FILE * fp = fopen(cmdpath, "r"); if (fp) { if (fgets(cmdline, defaultBuffSize, fp) == NULL) { STRCPY(cmdline, defaultBuffSize, "unknownProcess"); } fclose(fp); } if (strcmp(cmdline, "") == 0) { snprintf(cmdline, defaultBuffSize - 1, "unknownProcess"); } else { for (int i = 0; i < defaultBuffSize && cmdline[i] != '\0'; i++) { // If $APPNAME launches another process this another process is named "$APPNAME:another_process". if (cmdline[i] == ':') { cmdline[i] = '\0'; break; } } char* pch = strrchr(cmdline, '/'); unsigned int i = 0; if (pch != NULL) { pch++; //remove last occurrence of '/' for (; i < defaultBuffSize - (pch - cmdline) && pch[i] != '\0'; i++) { cmdline[i] = pch[i]; } } cmdline[i] = '\0'; } size_t pathLen = strnlen(outputDirectoryCopy, bufSize); if (pathLen < bufSize) { //check latest mark and add pid number before backslash if (pathLen > 1 && outputDirectoryCopy[pathLen - 1] != '/') { outputDirectoryCopy[pathLen] = '/'; pathLen++; } if (pidEnabled) { snprintf(outputDirectoryCopy + pathLen, bufSize - pathLen, "%s_%u/", cmdline, pid); } else { snprintf(outputDirectoryCopy + pathLen, bufSize - pathLen, "%s/", cmdline); } } } struct stat statbuf; unsigned int i = 0; while (i < bufSize - 1) { if ((outputDirectoryCopy[i] == '/' && i != 0 ) || outputDirectoryCopy[i] == '\0') { path[i] = '\0'; if (stat(path, &statbuf) != 0) //direcory doesn't exist { //create dir if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) { pathBuf[0] = '\0'; free(path); return ret; } } else { if (!S_ISDIR(statbuf.st_mode)) //not dir { pathBuf[0]= '\0'; free(path); return ret; } } if (outputDirectoryCopy[i] == '\0') { break; } } path[i] = outputDirectoryCopy[i]; i++; } if (i < bufSize-1) //fails if outputDirectory is longer than the bufSize { unsigned int length = (unsigned int)strlen(path); length = (bufSize-1 < length) ? bufSize-1 : length; memcpy(pathBuf, path, length); pathBuf[length] = 0; } else { pathBuf[0] = '\0'; } free(path); #endif //#elif !defined(_WIN32) return ret; } /*****************************************************************************\ Inline Function: CreateAppOutputDir Description: Creates folder path based on outputDirectory string. Then writes it in pathBuf. Input: unsigned int bufSize const char* outputDirectory Output: char* pathBuf int ret - return value: 0 - success, -1 - fail \*****************************************************************************/ inline int CreateAppOutputDir( char* pathBuf, unsigned int bufSize, const char* outputDirectory ) { int ret = CreateAppOutputDir( pathBuf, bufSize, outputDirectory, true, true, false ); return ret; } /*****************************************************************************\ Inline Function: ParentDirectoryCreate Description: Creates a directory to hold the given file \*****************************************************************************/ inline int ParentDirectoryCreate(const char * filePath) { #if defined _WIN32 || _WIN64 #else #include #ifndef MAX_PATH #define MAX_PATH PATH_MAX #endif #endif char pathBuf[MAX_PATH]; char parentBuf[MAX_PATH]; #if defined _WIN32 || _WIN64 char drive[MAX_PATH]; char directory[MAX_PATH]; if (_splitpath_s( filePath, drive, sizeof(drive), directory, sizeof(directory), NULL, 0, NULL, 0) != 0) { return -1; } _makepath(parentBuf, drive, directory, NULL, NULL); #else // dirname may alter its parameter, so copy it to a buffer first. STRCPY(pathBuf, MAX_PATH, filePath); STRCPY(parentBuf, MAX_PATH, dirname(pathBuf)); #endif return CreateAppOutputDir(pathBuf, sizeof(pathBuf), parentBuf, false, false, false); } } // iSTD #if defined _WIN32 # pragma warning(pop) #endif intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/FloatSafe.h000066400000000000000000001371211363533017100244070ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #include namespace iSTD { /*****************************************************************************\ Constants: FPU_FLOAT32_* Description: Binary representation of 32-bit floating point specials. FPU_FLOAT32_COMPUTE special value can be used in result tables to mark cases, where final value should be computed normally. \*****************************************************************************/ const DWORD FPU_FLOAT32_NAN = 0x7FFFFFFF; const DWORD FPU_FLOAT32_NEG_INF = 0xFF800000; const DWORD FPU_FLOAT32_POS_INF = 0x7F800000; const DWORD FPU_FLOAT32_NEG_ZERO = 0x80000000; const DWORD FPU_FLOAT32_POS_ZERO = 0x00000000; const DWORD FPU_FLOAT32_COMPUTE = 0xFFFFFFFF; const DWORD FPU_FLOAT32_ONE = (DWORD) 0x3F800000; const DWORD FPU_FLOAT32_MINUS_ONE = (DWORD) 0xBF800000; /*****************************************************************************\ Enumeration: FPU_FLOAT_CLASS Description: Classes of floating point numbers. (+0, -0, +finite, -finite, +Inf, -Inf, NaN, -denorm, +denorm) \*****************************************************************************/ enum FPU_FLOAT_CLASS { FPU_FLOAT_CLASS_NEG_INF = 0, FPU_FLOAT_CLASS_NEG_FINITE = 1, FPU_FLOAT_CLASS_NEG_DENORM = 2, FPU_FLOAT_CLASS_NEG_ZERO = 3, FPU_FLOAT_CLASS_POS_ZERO = 4, FPU_FLOAT_CLASS_POS_DENORM = 5, FPU_FLOAT_CLASS_POS_FINITE = 6, FPU_FLOAT_CLASS_POS_INF = 7, FPU_FLOAT_CLASS_NAN = 8, NUM_FPU_FLOAT_CLASSES = 9 }; /*****************************************************************************\ Inline Function: Float32GetClass Description: Returns class (+0, -0, +finite, -finite, +Inf, -Inf, NaN) of 32-bit float. \*****************************************************************************/ inline FPU_FLOAT_CLASS Float32GetClass( const float f ) { FLOAT32 f32; f32.value.f = f; switch( f32.value.u ) { case FPU_FLOAT32_POS_ZERO: return FPU_FLOAT_CLASS_POS_ZERO; case FPU_FLOAT32_NEG_ZERO: return FPU_FLOAT_CLASS_NEG_ZERO; case FPU_FLOAT32_POS_INF: return FPU_FLOAT_CLASS_POS_INF; case FPU_FLOAT32_NEG_INF: return FPU_FLOAT_CLASS_NEG_INF; default: break; } if( f32.exponent == 0xFF ) { return FPU_FLOAT_CLASS_NAN; } else if( f32.exponent == 0x00 ) { if( f32.sign == 0 ) { return FPU_FLOAT_CLASS_POS_DENORM; } else { return FPU_FLOAT_CLASS_NEG_DENORM; } } if( f32.sign ) { return FPU_FLOAT_CLASS_NEG_FINITE; } return FPU_FLOAT_CLASS_POS_FINITE; } /*****************************************************************************\ Inline Function: Float32IsInfinity Description: Returns true if class is +Inf or -Inf of 32-bit float. \*****************************************************************************/ inline bool Float32IsInfinity( const float f ) { FPU_FLOAT_CLASS fClass = Float32GetClass( f ); return ( fClass == FPU_FLOAT_CLASS_POS_INF ) || ( fClass == FPU_FLOAT_CLASS_NEG_INF ); } /*****************************************************************************\ Inline Function: Float32IsDenorm Description: Returns true if class is +Denorm or -Denorm. \*****************************************************************************/ inline bool Float32IsDenorm( const float f ) { FPU_FLOAT_CLASS fClass = Float32GetClass( f ); return ( fClass == FPU_FLOAT_CLASS_NEG_DENORM ) || ( fClass == FPU_FLOAT_CLASS_POS_DENORM ); } /*****************************************************************************\ Inline Function: Float32IsFinite Description: Returns true if f is finite: not +/-INF, and not NaN. \*****************************************************************************/ inline bool Float32IsFinite( const float f ) { FPU_FLOAT_CLASS fClass = Float32GetClass( f ); return ( fClass != FPU_FLOAT_CLASS_NAN ) && ( fClass != FPU_FLOAT_CLASS_NEG_INF ) && ( fClass != FPU_FLOAT_CLASS_POS_INF ); } /*****************************************************************************\ Inline Function: IsFPZero Description: Returns true if the argument x seen as a 32-bit IEEE754 floating point number is either positive or negative zero +0.0, -0.0. Input: dword value that will be interpreted as a binary32 representation of single-precision floating point value. Output: True if the value represents either positive or negative float zero. \*****************************************************************************/ inline bool IsFPZero( const DWORD x ) { return ( x == iSTD::FPU_FLOAT32_POS_ZERO ) || ( x == iSTD::FPU_FLOAT32_NEG_ZERO ); } /*****************************************************************************\ Inline Function: Float32SafeAdd Description: Performs addition taking care of floating point specials in software. \*****************************************************************************/ inline float Float32SafeAdd( const float arg1, const float arg2, const bool denormRetain ) { // Table for handling IEEE 754 specials in addition // // a + b -Inf -X -0 +0 +X +Inf NaN // // -Inf -Inf -Inf -Inf -Inf -Inf NaN NaN // -X -Inf +Inf NaN // -0 -Inf -0 +0 +Inf NaN // +0 -Inf +0 +0 +Inf NaN // +X -Inf +Inf NaN // +Inf NaN +Inf +Inf +Inf +Inf +Inf NaN // NaN NaN NaN NaN NaN NaN NaN NaN // static const DWORD RESULT[NUM_FPU_FLOAT_CLASSES][NUM_FPU_FLOAT_CLASSES] = { // -Inf -X -denorm -0 +0 +denorm +X +Inf NaN { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // -Inf { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // -X { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_NEG_ZERO , FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // -denorm { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_NEG_ZERO , FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // -0 { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_ZERO , FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // +0 { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_ZERO , FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // +denorm { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // +X { FPU_FLOAT32_NAN , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // +Inf { FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // NaN }; const FPU_FLOAT_CLASS t1 = Float32GetClass( arg1 ); const FPU_FLOAT_CLASS t2 = Float32GetClass( arg2 ); FLOAT32 f32; f32.value.u = RESULT[ t1 ][ t2 ]; bool computeDenorms = ( denormRetain && ( Float32IsDenorm( arg1 ) || Float32IsDenorm( arg2 ) ) ); if( ( f32.value.u == FPU_FLOAT32_COMPUTE ) || ( computeDenorms ) ) { return arg1 + arg2; } return f32.value.f; } /*****************************************************************************\ Inline Function: Float32SafeSubtract Description: Performs subtraction taking care of floating point specials in software. \*****************************************************************************/ inline float Float32SafeSubtract( const float arg1, const float arg2, const bool denormRetain ) { FLOAT32 f32; f32.value.f = arg2; // flip sign bit f32.sign ^= 1; return Float32SafeAdd( arg1, f32.value.f, denormRetain ); } /*****************************************************************************\ Inline Function: Float32SafeMultiply Description: Performs multiplication taking care of floating point specials in software. \*****************************************************************************/ inline float Float32SafeMultiply( const float arg1, const float arg2, const bool denormRetain ) { // Table for handling IEEE 754 specials in multiplication // // a * b -Inf -X -0 +0 +X +Inf NaN // // -Inf +Inf +Inf NaN NaN -Inf -Inf NaN // -X +Inf +0 -0 -Inf NaN // -0 NaN +0 +0 -0 -0 NaN NaN // +0 NaN -0 -0 +0 +0 NaN NaN // +X -Inf -0 +0 +Inf NaN // +Inf -Inf -Inf NaN NaN +Inf +Inf NaN // NaN NaN NaN NaN NaN NaN NaN NaN // static const DWORD RESULT[NUM_FPU_FLOAT_CLASSES][NUM_FPU_FLOAT_CLASSES] = { // -Inf -X -denorm -0 +0 +denorm +X +Inf NaN { FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NAN }, // -Inf { FPU_FLOAT32_POS_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_COMPUTE , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NAN }, // -X { FPU_FLOAT32_NAN , FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // -denorm { FPU_FLOAT32_NAN , FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // -0 { FPU_FLOAT32_NAN , FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // +0 { FPU_FLOAT32_NAN , FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // +denorm { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // +X { FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN }, // +Inf { FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // NaN }; FPU_FLOAT_CLASS t1 = Float32GetClass( arg1 ); FPU_FLOAT_CLASS t2 = Float32GetClass( arg2 ); FLOAT32 f32; f32.value.u = RESULT[ t1 ][ t2 ]; bool computeDenorms = ( denormRetain && ( Float32IsDenorm( arg1 ) || Float32IsDenorm( arg2 ) ) ); if( ( f32.value.u == FPU_FLOAT32_COMPUTE ) || ( computeDenorms ) ) { return arg1 * arg2; } return f32.value.f; } /*****************************************************************************\ Inline Function: Float32SafeFMA Description: Performs fused mutliply and add taking care of floating point specials in software. This is machine generated code provided by SSG. \*****************************************************************************/ inline float Float32SafeFMA( const float a, const float b, const float c ) { const DWORD _own_large_value_32[] = { 0x71800000, 0xf1800000 }; const DWORD _own_small_value_32[] = { 0x0d800000, 0x8d800000 }; const DWORD _ones[] = { 0x3f800000, 0xbf800000 }; DWORD ux = 0; DWORD uy = 0; DWORD uz = 0; DWORD ur = 0; DWORD xbits = 0; DWORD ybits = 0; DWORD zbits = 0; DWORD uhi = 0; DWORD ulo = 0; DWORD vhi = 0; DWORD vlo = 0; DWORD remain = 0; DWORD temp = 0; DWORD L_mask = 0; DWORD R_mask = 0; INT zsign = 0; INT rsign = 0; INT xexp = 0; INT yexp = 0; INT zexp = 0; INT rexp = 0; INT carry = 0; INT borrow = 0; INT rm = 0; INT shift = 0; INT L_shift = 0; INT R_shift = 0; UINT64 ubits = 0; float resultf = 0; float tv = 0; float x = a; float y = b; float z = c; // Set to round to nearest even. rm = 0; ux = FLOAT32( x >= 0.0f ? x : -x ).value.u; uy = FLOAT32( y >= 0.0f ? y : -y ).value.u;; uz = FLOAT32( z >= 0.0f ? z : -z ).value.u;; int cond1 = ( ux == 0 ) | ( ux >= 0x7f800000 ) | ( ux == 0x3f800000 ) | ( uy == 0 ) | ( uy >= 0x7f800000 ) | ( uy == 0x3f800000 ) | ( uz == 0 ) | ( uz >= 0x7f800000 ); if( cond1 != 0 ) { if( Float32IsInfinity( z ) && !Float32IsInfinity( x ) && !Float32IsInfinity( y ) ) { resultf = ( z + x ) + y; } else { resultf = x * y + z; } return resultf; } xexp = (int)( ux >> 23 ); yexp = (int)( uy >> 23 ); zexp = (int)( uz >> 23 ); xbits = 0x00800000 | ( ux & 0x007fffff ); ybits = 0x00800000 | ( uy & 0x007fffff ); zbits = 0x00800000 | ( uz & 0x007fffff ); rsign = ( FLOAT32(x).value.s ^ FLOAT32(y).value.s ) & 0x80000000; rexp = ( xexp + yexp ) - 0x7F; ubits = (UINT64)xbits * ybits; if( (DWORD) ( ubits >> 32 ) & 0x00008000 ) { uhi = (DWORD)( ubits >> 24 ); ulo = ( (DWORD)ubits << 8 ); rexp++; } else { uhi = (DWORD)( ubits >> 23 ); ulo = ( (DWORD)ubits << 9 ); } int cond2 = ( rexp > zexp ) | ( ( rexp == zexp ) & ( uhi >= zbits ) ); if( cond2 != 0 ) { shift = ( rexp - zexp ); vhi = zbits; vlo = 0; zsign = FLOAT32(z).value.s & 0x80000000; } else { shift = ( zexp - rexp ); rexp = zexp; vhi = uhi; vlo = ulo; uhi = zbits; ulo = 0; zsign = rsign; rsign = FLOAT32(z).value.s & 0x80000000; } remain = 0; if( shift != 0 ) { if( shift < 32 ) { L_shift = 32 - shift; R_shift = shift - 0; L_mask = ~( 0xffffffffu >> R_shift ); remain = ( vlo << L_shift ); vlo = ( ( vhi << L_shift ) & L_mask) | ( vlo >> R_shift ); vhi = ( vhi >> R_shift ); } else if( shift < 64 ) { L_shift = 64 - shift; R_shift = shift - 32; L_mask = ~( 0xffffffffu >> R_shift ); remain = ( ( vhi << L_shift ) & L_mask ) | ( vlo != 0 ); vlo = ( vhi >> R_shift ); vhi = 0; } else { remain = ( vhi | vlo ) != 0; vhi = vlo = 0; } } if( rsign == zsign ) { temp = ulo; ulo += vlo; carry = ( ulo < temp ); uhi += ( vhi + carry ); if ( uhi & 0x01000000 ) { remain = ( uhi << 31 ) | ( ( ulo | remain ) != 0 ); ur = ( uhi >> 1 ) & 0x007fffff; rexp += 1; } else { remain = ulo | ( remain != 0 ); ur = (uhi & 0x007fffff); } } else { remain = ( 0 - remain ); borrow = ( remain != 0 ); temp = ulo; ulo -= borrow; borrow = ( ulo > temp ); uhi -= borrow; temp = ulo; ulo -= vlo; borrow = ( ulo > temp ); uhi -= borrow; uhi -= vhi; if( uhi != 0 ) { temp = ( uhi << 8 ); shift = 0; } else if( ulo != 0 ) { temp = ulo; shift = 24; } else if( remain != 0 ) { temp = remain; shift = 24 + 32; } else { return FLOAT32( (DWORD)0x00000000 ).value.f; } shift += clz( temp ); if( shift < 32 ) { L_shift = shift - 0; R_shift = 32 - shift; R_mask = ( (DWORD) 1 << L_shift ) - 1; ur = ( ( uhi << L_shift ) | (( ulo >> R_shift ) & R_mask ) ) & 0x007fffff; remain = ( ulo << L_shift ) | ( remain != 0 ); } else if( shift < 64 ) { L_shift = shift - 32; R_shift = 64 - shift; R_mask = ( (DWORD) 1 << L_shift ) - 1; ur = ( ( ulo << L_shift ) | ( ( remain >> R_shift ) & R_mask ) ) & 0x007fffff; remain = ( remain << L_shift ); } else { L_shift = shift - 64; ur = ( remain << L_shift ) & 0x007fffff; remain = 0; } rexp -= shift; } if( (DWORD) rexp - 1 >= 0xFF - 1 ) { if( rexp >= 0xFF ) { rsign = ( (DWORD)rsign >> 31 ); if( rsign ) { resultf = tv = FLOAT32(_own_large_value_32[(1)]).value.f * FLOAT32(_own_large_value_32[0]).value.f; } else { resultf = tv = FLOAT32(_own_large_value_32[(0)]).value.f * FLOAT32(_own_large_value_32[0]).value.f; } return resultf; } else { //enters here only for rexp = 0 L_shift = 31; R_shift = 1; L_mask = ~(0xffffffffu >> R_shift ); ur |= 0x00800000; remain = ( ( ur << L_shift ) & L_mask ) | ( remain != 0 ); ur = ( ur >> R_shift ); } } else { ur |= ( rexp << 23 ); } if( remain != 0 ) { tv = ( ( (float *)_ones)[0] + ( (float *)_own_small_value_32)[0] ); int cond3, cond4, cond5, cond6; switch( rm ) { case ( 0 << 10 ): cond3 = ( ( remain & 0x80000000 ) != 0 ) & ( ( ( ur & 1 ) != 0 ) | ( ( remain & ~0x80000000 ) != 0 ) ); if( cond3 != 0 ) { ur++; if( ur >= 0x7f800000 ) { rsign = ( (unsigned)rsign >> 31 ); if( rsign ) { resultf = tv = ( ( (float *) _own_large_value_32)[1] * ( (float *) _own_large_value_32)[0] ); } else { resultf = tv = (((float *) _own_large_value_32)[(0)] * ((float *) _own_large_value_32)[0]); } return resultf; } } case ( 3 << 10 ): cond4 = ( ur < 0x00800000 ) | ( (ur == 0x00800000 ) & ( remain == 0x80000000 ) ); if( cond4 != 0 ) { tv = ( ( ( float *)_own_small_value_32)[0] * ( ( float *)_own_small_value_32)[0] ); } break; case ( 2 << 10 ): cond5 = ( rsign & ( ur < 0x00800000 ) ) | ( (!rsign) & ( (ur < 0x007fffff ) | ( ( ur == 0x007fffff ) & ( remain < 0x80000000 ) ) ) ); if( cond5 != 0 ) { tv = ( ( (float *)_own_small_value_32)[0] * ( (float *)_own_small_value_32)[0] ); } if( !rsign ) { ur++; if( ur >= 0x7f800000 ) { //rsign = ((unsigned) rsign >> 31); resultf = tv = ( ( (float *)_own_large_value_32)[0] * ( (float *)_own_large_value_32)[0] ); return resultf; } } break; case ( 1 << 10 ): cond6 = ( !rsign & ( ur < 0x00800000 ) ) | ( rsign & ( (ur < 0x007fffff ) | ( ( ur == 0x007fffff ) & ( remain < 0x80000000 ) ) ) ); if( cond6 != 0 ) { tv = ( ( (float *)_own_small_value_32)[0] * ( (float *)_own_small_value_32)[0] ); } if( rsign ) { ur++; if (ur >= 0x7f800000 ) { //rsign = ((unsigned) rsign >> 31); resultf = tv = ( ( (float *)_own_large_value_32)[1] * ( (float *)_own_large_value_32)[0] ); return resultf; } } break; } } resultf = FLOAT32( (DWORD) (rsign | ur ) ).value.f; return resultf; } /*****************************************************************************\ Inline Function: Float32SafeRSQRT Description: Performs correctly rounded single precision reciprocal square root operation taking care of floating point specials in software. \*****************************************************************************/ inline float Float32SafeRSQRT( const float arg, bool denormRetain ) { static const DWORD RESULT[NUM_FPU_FLOAT_CLASSES] = { FPU_FLOAT32_NAN, // rsqrt( -inf ) = NaN FPU_FLOAT32_NAN, // rsqrt( -X ) = NaN //but to be really OK,we should try to maintain the NaN payload FPU_FLOAT32_NAN, // rsqrt( -denorm ) = NaN //but to be really OK,we should try to maintain the NaN payload FPU_FLOAT32_NEG_INF, // rsqrt( -0 ) = -inf FPU_FLOAT32_POS_INF, // rsqrt( +0 ) = +inf FPU_FLOAT32_COMPUTE, // rsqrt( +denorm) = computed value FPU_FLOAT32_COMPUTE, // rsqrt( +X ) == computed value FPU_FLOAT32_POS_ZERO, // rsqrt( +inf ) == +0.0 FPU_FLOAT32_NAN // rsqrt( NaN ) == NaN }; FPU_FLOAT_CLASS t1 = Float32GetClass( arg ); FLOAT32 f32; f32.value.u = RESULT[ t1 ]; bool computeDenorms = denormRetain && Float32IsDenorm( arg ); if ( !computeDenorms && t1 == FPU_FLOAT_CLASS_NEG_DENORM ) { f32.value.u = FPU_FLOAT32_NEG_INF; } if ( !computeDenorms && t1 == FPU_FLOAT_CLASS_POS_DENORM ) { f32.value.u = FPU_FLOAT32_POS_INF; } if( ( f32.value.u == FPU_FLOAT32_COMPUTE ) || ( computeDenorms ) ) { double darg = arg; double s = sqrt(darg); //double-precision square root double result = 1.0 / s; //double-precision division return static_cast(result); //back to floats } return f32.value.f; } /*****************************************************************************\ Inline Function: Float32SafeDivide Description: Performs division taking care of floating point specials in software. \*****************************************************************************/ inline float Float32SafeDivide( const float arg1, const float arg2, const bool denormRetain ) { // Table for handling IEEE 754 specials in division // // a / b -Inf -X -0 +0 +X +Inf NaN // // -Inf NaN +Inf +Inf -Inf -Inf NaN NaN // -X +0
+Inf -Inf
-0 NaN // -0 +0 +0 NaN NaN -0 -0 NaN // +0 -0 -0 NaN NaN +0 +0 NaN // +X -0
-Inf +Inf
+0 NaN // +Inf NaN -Inf -Inf +Inf +Inf NaN NaN // NaN NaN NaN NaN NaN NaN NaN NaN // static const DWORD RESULT[NUM_FPU_FLOAT_CLASSES][NUM_FPU_FLOAT_CLASSES] = { // -Inf -X -denorm -0 +0 +denorm +X +Inf NaN { FPU_FLOAT32_NAN , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // -Inf { FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NAN }, // -X { FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NAN }, // -denorm { FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NAN }, // -0 { FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NAN }, // +0 { FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NAN }, // +denorm { FPU_FLOAT32_NEG_ZERO, FPU_FLOAT32_COMPUTE , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_COMPUTE , FPU_FLOAT32_POS_ZERO, FPU_FLOAT32_NAN }, // +X { FPU_FLOAT32_NAN , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_NEG_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_POS_INF , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // +Inf { FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN , FPU_FLOAT32_NAN }, // NaN }; FPU_FLOAT_CLASS t1 = Float32GetClass( arg1 ); FPU_FLOAT_CLASS t2 = Float32GetClass( arg2 ); FLOAT32 f32; f32.value.u = RESULT[ t1 ][ t2 ]; bool computeDenorms = ( denormRetain && ( Float32IsDenorm( arg1 ) || Float32IsDenorm( arg2 ) ) ); if( ( f32.value.u == FPU_FLOAT32_COMPUTE ) || ( computeDenorms ) ) { return arg1 / arg2; } return f32.value.f; } /*****************************************************************************\ Inline Function: Signed32SafeDivideQuotient Description: Computes src0 divided by src1 Table for handling signed divide quotient and remainder: IDIV SRC0 SRC1 +INT -INT 0 +INT +INT -INT 0 -INT -INT +INT 0 0 Q:0x7FFFFFFF Q: 0x80000000 Q:0x7FFFFFFF R:0x7FFFFFFF R: 0x80000000 R:0x7FFFFFFF \*****************************************************************************/ inline signed long Signed32SafeDivideQuotient( const signed long src0, const signed long src1 ) { if( !src1 ) { if( src0 < 0 ) { return LONG_MIN; } return LONG_MAX; } return src0 / src1; } /*****************************************************************************\ Inline Function: Signed32SafeDivideRemainder Description: Computes remainder of src0 divided by src1 \*****************************************************************************/ inline signed long Signed32SafeDivideRemainder( const signed long src0, const signed long src1 ) { if( !src1 ) { if( src0 < 0 ) { return LONG_MIN; } return LONG_MAX; } return src0 % src1; } /*****************************************************************************\ Inline Function: Unsigned32SafeDivideQuotient Description: Computes src0 divided by src1 Table for handling unsigned divide quotient and remainder UDIV SRC0 SRC1 <>0 0 <>0 UINT 0 0 Q:0xFFFFFFFF Q:0xFFFFFFFF R:0xFFFFFFFF R:0xFFFFFFFF \*****************************************************************************/ inline DWORD Unsigned32SafeDivideQuotient( const DWORD src0, const DWORD src1 ) { if( !src1 ) { return UINT_MAX; } return src0 / src1; } /*****************************************************************************\ Inline Function: Unsigned32SafeDivideRemainder Description: Computes remainder of src0 divided by src1 \*****************************************************************************/ inline DWORD Unsigned32SafeDivideRemainder( const DWORD src0, const DWORD src1 ) { if( !src1 ) { return UINT_MAX; } return src0 % src1; } /*****************************************************************************\ Inline Function: F32ToF16_d Description: Float32 to float16 conversion based on "Fast Half Float Conversions" by Jeroen van der Zijp Input: 32-bit DWORD represantation of float value Output: 16-bit DWORD represantation of float value \*****************************************************************************/ inline WORD F32ToF16_d( DWORD arg ) { static const WORD btbl[512] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100, 0x0200,0x0400,0x0800,0x0c00,0x1000,0x1400,0x1800,0x1c00,0x2000,0x2400,0x2800,0x2c00,0x3000,0x3400,0x3800,0x3c00, 0x4000,0x4400,0x4800,0x4c00,0x5000,0x5400,0x5800,0x5c00,0x6000,0x6400,0x6800,0x6c00,0x7000,0x7400,0x7800,0x7c00, 0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00, 0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00, 0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00, 0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00, 0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00, 0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00, 0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00,0x7c00, 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000, 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8001,0x8002,0x8004,0x8008,0x8010,0x8020,0x8040,0x8080,0x8100, 0x8200,0x8400,0x8800,0x8c00,0x9000,0x9400,0x9800,0x9c00,0xa000,0xa400,0xa800,0xac00,0xb000,0xb400,0xb800,0xbc00, 0xc000,0xc400,0xc800,0xcc00,0xd000,0xd400,0xd800,0xdc00,0xe000,0xe400,0xe800,0xec00,0xf000,0xf400,0xf800,0xfc00, 0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00, 0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00, 0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00, 0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00, 0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00, 0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00, 0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00,0xfc00 }; static const unsigned char stbl[512] = { 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f, 0x0e,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d, 0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0d, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f, 0x0e,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d, 0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0d }; DWORD sexp = (arg>>23)&0x1ff; return (WORD)(btbl[ sexp ]+( (arg&0x007fffff)>>stbl[ sexp ] )); } /*****************************************************************************\ Inline Function: F32ToF16_f Description: Float32 to float16 conversion based on "Fast Half Float Conversions" by Jeroen van der Zijp Input: 32-bit float value Output: 16-bit WORD represantation of float value \*****************************************************************************/ inline WORD F32ToF16_f( float arg ) { return F32ToF16_d( *(DWORD *)&arg ); } /*****************************************************************************\ Inline Function: F16ToF32 Description: Float16 to float32 conversion Input: 16-bit WORD representation of float16 value Output: 32-bit DWORD represantation of float32 value \*****************************************************************************/ static inline DWORD F16ToF32( WORD v ) { unsigned long index; return // is exponent!=0 ? v & 0x7C00 // is exponent==max ? ? ( v & 0x7C00 ) == 0x7C00 // is mantissa!=0 ? ? v & 0x03FF // convert NaN ? ( ( v << 13 ) + 0x70000000 ) | 0x7f800000 // convert infinities : ( v << 16 ) | 0x7f800000 // convert normalized values : ( ( ( v << 13 ) + 0x70000000 ) & ~0x70000000 ) + 0x38000000 // is mantissa non-zero ? : v & 0x03FF // convert denormalized values ? index=bsr( v & 0x03FF ), ( ( ( ( v << 16 ) & 0x80000000 ) | ( ( v << 13 ) & 0xF800000 ) ) + 0x33800000 + ( index << 23 ) ) | ( ( ( v & 0x03FF ) << ( 23-index ) ) & ~0x800000 ) // convert zeros : v << 16; } /*****************************************************************************\ Inline Function: Float32SafeMax Description: MinMax of Floating Point Numbers. Input: arg1 arg2 isGen7 Output: max( arg1, arg2 ) \*****************************************************************************/ inline float Float32SafeMax( const float arg1, const float arg2, bool isGen7 ) { // Values of following arrays corresponds to results of sel.l instructions. static const bool RESULT_preGen7[NUM_FPU_FLOAT_CLASSES][NUM_FPU_FLOAT_CLASSES] = { // -Inf -X -denorm -0 +0 +denorm +X +Inf NaN { true , false , false , false , false , false , false , false , true }, // -Inf { true , false , false , false , false , false , false , false , true }, // -X { true , true , true , true , true , true , false , false , true }, // -denorm { true , true , true , true , true , true , false , false , true }, // -0 { true , true , true , true , true , true , false , false , true }, // +0 { true , true , true , true , true , true , false , false , true }, // +denorm { true , true , true , true , true , true , false , false , true }, // +X { true , true , true , true , true , true , true , true , true }, // +Inf { false , false , false , false , false , false , false , false , false }, // NaN }; static const bool RESULT_Gen7[NUM_FPU_FLOAT_CLASSES][NUM_FPU_FLOAT_CLASSES] = { // -Inf -X -denorm -0 +0 +denorm +X +Inf NaN { true , false , false , false , false , false , false , false , true }, // -Inf { true , false , false , false , false , false , false , false , true }, // -X { true , true , true , true , true , true , false , false , true }, // -denorm { true , true , true , true , false , true , false , false , true }, // -0 { true , true , true , true , true , true , false , false , true }, // +0 { true , true , true , true , true , true , false , false , true }, // +denorm { true , true , true , true , true , true , false , false , true }, // +X { true , true , true , true , true , true , true , true , true }, // +Inf { false , false , false , false , false , false , false , false , false }, // NaN }; const FPU_FLOAT_CLASS t1 = Float32GetClass( arg1 ); const FPU_FLOAT_CLASS t2 = Float32GetClass( arg2 ); if( ( t1 == FPU_FLOAT_CLASS_NEG_FINITE || t1 == FPU_FLOAT_CLASS_POS_FINITE ) && ( t2 == FPU_FLOAT_CLASS_NEG_FINITE || t2 == FPU_FLOAT_CLASS_POS_FINITE ) ) { return ( arg1 >= arg2 ) ? arg1 : arg2; } FLOAT32 f32; if( isGen7 ) { f32.value.f = ( RESULT_Gen7[t1][t2] ) ? arg1 : arg2; } else { f32.value.f = ( RESULT_preGen7[t1][t2] ) ? arg1 : arg2; } return f32.value.f; } /*****************************************************************************\ Inline Function: Float32SafeMin Description: MinMax of Floating Point Numbers. Input: arg1 arg2 isGen7 Output: max( arg1, arg2 ) \*****************************************************************************/ inline float Float32SafeMin( const float arg1, const float arg2, bool isGen7 ) { // Values of following arrays corresponds to results of sel.ge instruction. static const bool RESULT_preGen7[NUM_FPU_FLOAT_CLASSES][NUM_FPU_FLOAT_CLASSES] = { // -Inf -X -denorm -0 +0 +denorm +X +Inf NaN { false , true , true , true , true , true , true , true , true }, // -Inf { false , false , true , true , true , true , true , true , true }, // -X { false , false , false , false , false , false , true , true , true }, // -denorm { false , false , false , false , false , false , true , true , true }, // -0 { false , false , false , false , false , false , true , true , true }, // +0 { false , false , false , false , false , false , true , true , true }, // +denorm { false , false , false , false , false , false , false , true , true }, // +X { false , false , false , false , false , false , false , false , true }, // +Inf { false , false , false , false , false , false , false , false , false }, // NaN }; static const bool RESULT_Gen7[NUM_FPU_FLOAT_CLASSES][NUM_FPU_FLOAT_CLASSES] = { // -Inf -X -denorm -0 +0 +denorm +X +Inf NaN { false , true , true , true , true , true , true , true , true }, // -Inf { false , false , true , true , true , true , true , true , true }, // -X { false , false , false , false , false , false , true , true , true }, // -denorm { false , false , false , false , true , false , true , true , true }, // -0 { false , false , false , false , false , false , true , true , true }, // +0 { false , false , false , false , false , false , true , true , true }, // +denorm { false , false , false , false , false , false , false , true , true }, // +X { false , false , false , false , false , false , false , false , true }, // +Inf { false , false , false , false , false , false , false , false , false }, // NaN }; const FPU_FLOAT_CLASS t1 = Float32GetClass( arg1 ); const FPU_FLOAT_CLASS t2 = Float32GetClass( arg2 ); if( ( t1 == FPU_FLOAT_CLASS_NEG_FINITE || t1 == FPU_FLOAT_CLASS_POS_FINITE ) && ( t2 == FPU_FLOAT_CLASS_NEG_FINITE || t2 == FPU_FLOAT_CLASS_POS_FINITE ) ) { return ( arg1 < arg2 ) ? arg1 : arg2; } FLOAT32 f32; if( isGen7 ) { f32.value.f = ( RESULT_Gen7[t1][t2] ) ? arg1 : arg2; } else { f32.value.f = ( RESULT_preGen7[t1][t2] ) ? arg1 : arg2; } return f32.value.f; } /*****************************************************************************\ Inline Function: FloatSaturate Description: For a floating-point destination type, the saturation target range is [0.0, 1.0]. For a floating-point NaN, there is no "closest value"; any NaN saturates to 0.0. (...) Any floating-point number greater than 1.0, including +INF, saturates to 1.0. Any negative floating-point number, including -INF, saturates to 0.0. Any floating-point number in the range 0.0 to 1.0 is not changed by saturation. -0.0 is changed to +0.0. Input: const float f Output: float \*****************************************************************************/ inline float FloatSaturate( const float f ) { switch( Float32GetClass( f ) ) { case FPU_FLOAT_CLASS_NEG_INF: case FPU_FLOAT_CLASS_NEG_FINITE: case FPU_FLOAT_CLASS_NEG_DENORM: case FPU_FLOAT_CLASS_NEG_ZERO: case FPU_FLOAT_CLASS_POS_ZERO: case FPU_FLOAT_CLASS_NAN: return 0.f; case FPU_FLOAT_CLASS_POS_DENORM: return f; case FPU_FLOAT_CLASS_POS_FINITE: return ( f <= 1.f ) ? f : 1.f; case FPU_FLOAT_CLASS_POS_INF: return 1.f; default: ASSERT( 0 ); return 0.f; } } } // namespace iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/FloatUtil.h000066400000000000000000000342731363533017100244520ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "types.h" #include // for powf() namespace iSTD { /*****************************************************************************\ Inline Function: FloatToLong Description: converts a float to long using SSE, avoiding FP stack stall \*****************************************************************************/ __forceinline long FloatToLong( const float value ) { #if defined(_WIN32) && defined(_MSC_VER) return _mm_cvtsi128_si32( _mm_cvttps_epi32( _mm_set_ps1( value ) ) ); #else return (long)value; #endif } /*****************************************************************************\ Inline Function: Ceiling Description: Rounds a float up to the next integer value \*****************************************************************************/ __forceinline long Ceiling( const float value ) { long roundVal = FloatToLong( value ); if( ( value - roundVal ) != 0 ) { return roundVal + 1; } return roundVal; } /*****************************************************************************\ Inline Function: Scale Description: Scales a [0.0,1.0] float to [0,max] integer \*****************************************************************************/ __forceinline DWORD Scale( float value, DWORD max ) { ASSERT( CheckLimits( value, 0.0f, 1.0f ) ); return ( (DWORD)FloatToLong( (value) * (float)(max) ) ); } /*****************************************************************************\ Inline Function: Normalize Description: Normalize the floating-point value with the range [min,max] to [0.0f,1.0f] \*****************************************************************************/ __forceinline float Normalize( float value, float min, float max ) { return ( value - min ) / ( max - min ); } /*****************************************************************************\ Inline Function: Lerp Description: Linear-Interpolation \*****************************************************************************/ __forceinline float Lerp( float x, float y, float z ) { return ( ( x * ( 1 - z ) ) + ( y * z ) ); } /*****************************************************************************\ Inline Function: FloatToFixed Description: Converts a floating-point number to the specified fixed-point number \*****************************************************************************/ template __forceinline Type FloatToFixed( float value, const int whole, const int fractional, const int round = 0 ) { ASSERT( fractional + whole <= 32 ); // Optional floating point rounding precision value += ( round != 0 ) ? 0.5f * ( 1.0f / (float)( 1 << round ) ) : 0; Type fixed = (Type)FloatToLong( value * (float)( 1 << fractional ) ); #ifdef _DEBUG DWORD mask = 0xffffffff << ( whole + fractional ); ASSERT( (( fixed >= 0 ) && (( fixed & mask ) == 0 )) || (( fixed < 0 ) && (( fixed & mask ) == mask )) ); #endif return fixed; } /*****************************************************************************\ Inline Function: FixedToFloat Description: Converts the specified fixed-point number to a floating-point number \*****************************************************************************/ template __forceinline float FixedToFloat( Type fixed, const int whole, const int fractional ) { ASSERT( fractional + whole <= 32 ); //check sign bit if negative if (fixed >> (fractional + whole) != 0) { // pad the sign from left to 32 bit fixed |= (0xffffffff << (fractional + whole)); } float value = (float)fixed / (float)( 1 << fractional ); return value; } /*****************************************************************************\ Inline Function: Float32ToSnorm Description: Converts a 32bit float to a bitcount size SNORM value \*****************************************************************************/ template< DWORD bitcount > inline DWORD Float32ToSnorm( const float value ) { ASSERT( bitcount <= 32 ); long snormValue = 0; FLOAT32 f32; f32.value.f = value; // NaN -> 0 if( f32.exponent == BITMASK( 8 ) && f32.fraction != 0 ) { snormValue = 0; } else { const bool isPosInfinity = f32.exponent == BITMASK( 8 ) && f32.fraction == 0 && f32.sign == 0; const bool isNegInfinity = f32.exponent == BITMASK( 8 ) && f32.fraction == 0 && f32.sign == 1; // Clamp > 1.0f || +Inf -> 1.0f // Clamp < -1.0f || -Inf -> -1.0f if( f32.value.f > 1.0f || isPosInfinity ) { f32.value.f = 1.0f; } else if ( f32.value.f < -1.0f || isNegInfinity ) { f32.value.f = -1.0f; } // Convert float scale to integer scale f32.value.f *= (float)( ( 0x1 << ( bitcount - 1 ) ) - 1 ); // Convert to integer by rounding and dropping // the fractional part f32.value.f = ( f32.value.f >= 0 ) ? f32.value.f + 0.5f : f32.value.f - 0.5f; snormValue = FloatToLong( f32.value.f ); } return (DWORD)snormValue; } /*****************************************************************************\ Inline Function: Float32ToSnormSM Description: Converts a 32bit float to a bitcount size SNORM value in Sign Magnitude format (SM) \*****************************************************************************/ template< DWORD bitcount > inline DWORD Float32ToSnormSM( const float value ) { ASSERT( bitcount <= 32 ); long snormValue = 0; FLOAT32 f32; f32.value.f = value; // NaN -> 0 if( f32.exponent == BITMASK( 8 ) && f32.fraction != 0 ) { snormValue = 0; } else { const bool isPosInfinity = f32.exponent == BITMASK( 8 ) && f32.fraction == 0 && f32.sign == 0; const bool isNegInfinity = f32.exponent == BITMASK( 8 ) && f32.fraction == 0 && f32.sign == 1; // Clamp > 1.0f || +Inf -> 1.0f // Clamp < -1.0f || -Inf -> -1.0f if( f32.value.f > 1.0f || isPosInfinity ) { f32.value.f = 1.0f; } else if ( f32.value.f < -1.0f || isNegInfinity ) { f32.value.f = -1.0f; } // Convert float scale to integer scale f32.value.f *= (float)( ( 0x1 << ( bitcount - 1 ) ) - 1 ); // Convert to integer by rounding and dropping // the fractional part f32.value.f = ( f32.value.f >= 0 ) ? f32.value.f + 0.5f : f32.value.f - 0.5f; snormValue = FloatToLong( f32.value.f ); if(snormValue < 0) { snormValue *= -1; snormValue = snormValue | (0x1 << ( bitcount - 1 ) ); } } return (DWORD)snormValue; } /*****************************************************************************\ Inline Function: LinearToSRGB Description: Converts a 32bit float in linear space to SRGB space \*****************************************************************************/ inline float LinearToSRGB( const float value ) { float srgbValue = value; ASSERT( value >= 0.0f && value <= 1.0f ); if (value < 0.0f) { srgbValue = 0.0f; } else if( value < 0.0031308f ) { srgbValue = 12.92f * value; } else if (value < 1.0f) { srgbValue = ( 1.055f * powf( value, (1.0f/2.4f) ) ) - 0.055f; } else { srgbValue = 1.0f; } ASSERT( srgbValue >= 0.0f && srgbValue <= 1.0f ); return srgbValue; } /*****************************************************************************\ Inline Function: SRGBToLinear Description: Converts a 32bit float in SRGB space to linear space \*****************************************************************************/ inline float SRGBToLinear( const float value ) { float linearValue = value; ASSERT( value >= 0.0f && value <= 1.0f ); if( linearValue <= 0.04045f ) { linearValue = value / 12.92f; } else { linearValue = powf( ( ( value + 0.055f ) / 1.055f ), 2.4f ); } ASSERT( linearValue >= 0.0f && linearValue <= 1.0f ); return linearValue; } /*****************************************************************************\ Inline Function: Float32ToUnorm Description: Converts a 32bit float to a bitcount size UNORM value \*****************************************************************************/ template< DWORD bitcount > inline DWORD Float32ToUnorm( const float value ) { ASSERT( bitcount <= 32 ); DWORD unormValue = 0; FLOAT32 f32; f32.value.f = value; // NaN -> 0 if( f32.exponent == BITMASK( 8 ) && f32.fraction != 0 ) { unormValue = 0; } else { const bool isPosInfinity = f32.exponent == BITMASK( 8 ) && f32.fraction == 0 && f32.sign == 0; const bool isNegInfinity = f32.exponent == BITMASK( 8 ) && f32.fraction == 0 && f32.sign == 1; // Clamp > 1.0f || +Inf -> 1.0f // Clamp < 0.0f || -Inf -> 0.0f if( f32.value.f > 1.0f || isPosInfinity ) { f32.value.f = 1.0f; } else if ( f32.value.f < 0.0f || isNegInfinity ) { f32.value.f = 0.0f; } // Convert float scale to integer scale f32.value.f *= BITMASK( bitcount ); // Convert to integer by rounding and dropping // fractional bits f32.value.f += 0.5f; unormValue = (DWORD)FloatToLong( f32.value.f ); unormValue = (DWORD)f32.value.f; unormValue = Min( (DWORD)unormValue, (DWORD)BITMASK( bitcount ) ); } return unormValue; } /*****************************************************************************\ Inline Function: Float32ToFloat16 Description: Converts a 32bit float to a 16bit float \*****************************************************************************/ inline unsigned short Float32ToFloat16( const float value ) { FLOAT16 f16; f16.value.u = 0; FLOAT32 f32; f32.value.f = value; // +/-0 32bit -> +/- 0 16bit if( f32.exponent == 0 && f32.fraction == 0 ) { f16.exponent = 0; f16.fraction = 0; f16.sign = f32.sign; } // NaN 32bit -> NaN 16bit else if( f32.exponent == BITMASK( 8 ) && f32.fraction != 0 ) { f16.exponent = BITMASK( 5 ); f16.fraction = 0x1 << 9; f16.sign = 1; } // +/-Inf 32bit -> +/-Inf 16bit else if ( f32.exponent == BITMASK( 8 ) && f32.fraction == 0 ) { f16.exponent = BITMASK( 5 ); f16.fraction = 0; f16.sign = f32.sign; } else { const long ExpBias16 = 31 / 2; const long ExpBais32 = 255 / 2; const long expUnbiased = f32.exponent - ExpBais32; // 32bit normalized value out of minimum range of 16bit capacity // resulting in minimum non-denorm 16bit value if ( expUnbiased <= -25 ) { f16.exponent = 0; f16.fraction = 0; } // 32bit normalized value within the 16bit denormalized unbiased // exponent range else if( expUnbiased > -25 && expUnbiased < -14 ) { long adjustedUnbiasedExp = expUnbiased; unsigned long adjustedFranction = f32.fraction; // Shift the implicit 1 into the fraction, making implicit 0 // as denormalized format dictates adjustedFranction >>= 1; adjustedFranction |= ( 0x1 << 22 ); // Round off the fraction until the unbiased exponent is // within a denormalized representable range unsigned long denormShiftAmount = -1 * ( adjustedUnbiasedExp + 15 ); ASSERT( denormShiftAmount < 10 ); adjustedFranction >>= denormShiftAmount; adjustedUnbiasedExp += denormShiftAmount; f16.exponent = adjustedUnbiasedExp + ExpBias16; f16.fraction = ( adjustedFranction ) >> ( 23 - 10 ); // Assert that the 16bit is actually denormalized. The result // should never be 0 because of the addition of the implicit 1 ASSERT( f16.exponent == 0 && f16.fraction != 0 ); } // 32bit value out of maximum dynamic range of 16bit capacity // resulting in maximum 16bit value else if( expUnbiased > 15 ) { f16.exponent = 15 + ExpBias16; f16.fraction = BITMASK( 10 ); } // Otherwise, normalized down conversion falls within normalized // 16bit range else { f16.exponent = expUnbiased + ExpBias16; f16.fraction = ( f32.fraction ) >> ( 23 - 10 ); } // Sign is preserved under any circumstance f16.sign = f32.sign; } return f16.value.u; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/HashTable.h000066400000000000000000001251501363533017100243750ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #include "Array.h" #include "LinkedList.h" namespace iSTD { /*****************************************************************************\ Struct: IsHashTableTypeSupported \*****************************************************************************/ template struct IsHashTableTypeSupported { enum { value = false }; }; template<> struct IsHashTableTypeSupported { enum { value = true }; }; template<> struct IsHashTableTypeSupported { enum { value = true }; }; template<> struct IsHashTableTypeSupported { enum { value = true }; }; template<> struct IsHashTableTypeSupported { enum { value = true }; }; template<> struct IsHashTableTypeSupported { enum { value = true }; }; #ifndef __LP64__ // u/long on linux64 platform is 64-bit type and collides with U/INT64 template<> struct IsHashTableTypeSupported { enum { value = true }; }; template<> struct IsHashTableTypeSupported { enum { value = true }; }; #endif template<> struct IsHashTableTypeSupported { enum { value = true }; }; template<> struct IsHashTableTypeSupported { enum { value = true }; }; template<> struct IsHashTableTypeSupported { enum { value = true }; }; template struct IsHashTableTypeSupported { enum { value = true }; }; /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define HashTableTemplateList class KeyType, class ElementType, class CAllocatorType #define CHashTableType CHashTable /*****************************************************************************\ Class: CHashTable Description: Template Hash Table \*****************************************************************************/ template class CHashTable : public CObject { public: // HashKey definition - converts KeyType to HashCode class CHashKey : public CObject { public: CHashKey( void ); CHashKey( const KeyType &keyValue ); CHashKey( const KeyType &keyValue, const DWORD hashCode ); CHashKey( const CHashKey &hashKey ); virtual ~CHashKey( void ); DWORD GetHashCode( void ) const; const KeyType& GetKeyValue( void ) const; bool operator == ( const CHashKey &hashKey ) const; protected: #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable:4324 ) // structure was padded due to __declspec(align()) #endif ALIGN(16) KeyType m_KeyValue; ALIGN(16) DWORD m_HashCode; #ifdef _MSC_VER #pragma warning( pop ) #endif }; // Constructor \ Destructor CHashTable( const DWORD size ); virtual ~CHashTable( void ); // Interfaces using KeyType bool Add( const KeyType &key, const ElementType &element ); bool Get( const KeyType &key, ElementType &element ) const; bool Remove( const KeyType &key, ElementType &element ); bool Remove( const ElementType &element ); // Interfaces using HashKey bool Add( const CHashKey &hashKey, const ElementType &element ); bool Get( const CHashKey &hashKey, ElementType &element ) const; bool Remove( const CHashKey &hashKey, ElementType &element ); // Other interfaces bool IsEmpty( void ) const; DWORD GetCount( void ) const; void DebugPrint( void ) const; C_ASSERT( IsHashTableTypeSupported::value == true ); protected: // HashNode definition - hash table storage class CHashNode : public CObject { public: CHashNode( const CHashKey &hashKey, const ElementType &element ); virtual ~CHashNode( void ); const CHashKey& GetHashKey( void ) const; ElementType GetElement( void ) const; protected: CHashKey m_HashKey; ElementType m_Element; }; // Internal data structures - Array of Linked-Lists typedef CLinkedList CHashTableKeyList; typedef CArray CHashTableArray; CHashTableKeyList* CreateHashKeyList( void ); void DeleteHashKeyList( CHashTableKeyList* pHashKeyList ); CHashNode* CreateHashNode( const CHashKey &hashKey, const ElementType &element ); void DeleteHashNode( CHashNode* pHashNode ); DWORD GetHashSize( const DWORD size ) const; DWORD GetHashIndex( const CHashKey &hashKey ) const; // Internal data CHashTableArray m_HashArray; DWORD m_Count; #ifdef _DEBUG DWORD m_AddCount; DWORD m_RemoveCount; DWORD m_CollisionCount; #endif public: // Iterator definition class CIterator { public: CIterator( void ); CIterator( const CIterator &iterator ); CIterator& operator--( void ); CIterator& operator++( void ); bool operator==( const CIterator &iterator ) const; bool operator!=( const CIterator &iterator ) const; CIterator& operator=( const CIterator &iterator ); ElementType operator*( void ); const KeyType& GetKeyValue( void ); friend class CHashTable; protected: CHashTableArray* m_Array; DWORD m_ArrayIndex; typename CHashTableKeyList::CIterator m_Iterator; }; // Begin \ End iterators of HashTable CIterator Begin( void ) const; CIterator End( void ) const; // Interfaces using Iterator bool Add( const CHashKey &hashKey, const ElementType &element, CIterator &iterator ); bool Get( const CHashKey &hashKey, CIterator &iterator ) const; bool Remove( CIterator iterator ); }; /*****************************************************************************\ Function: CHashTable Constructor Description: Initializes internal data Input: const DWORD size - max size of the hash table Output: none \*****************************************************************************/ template CHashTableType::CHashTable( const DWORD size ) : CObject(), m_HashArray( GetHashSize( size ) ) { m_Count = 0; #ifdef _DEBUG m_AddCount = 0; m_RemoveCount = 0; m_CollisionCount = 0; #endif } /*****************************************************************************\ Function: CHashTable Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template CHashTableType::~CHashTable( void ) { const DWORD size = m_HashArray.GetSize(); for( DWORD i = 0; i < size; ++i ) { CHashTableKeyList* pHashKeyList = m_HashArray.GetElement(i); if( pHashKeyList ) { DeleteHashKeyList( pHashKeyList ); } } } /*****************************************************************************\ Function: CHashTable::Add Description: Adds an element to the hash table Input: const KeyType &key - the key to which the element is referenced const ElementType &element - the element to be added Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CHashTableType::Add( const KeyType &key, const ElementType &element ) { CHashKey hashKey( key ); return Add( hashKey, element ); } /*****************************************************************************\ Function: CHashTable::Get Description: Gets the element in the hash table referenced by the key Input: const KeyType &key - the key of the element to get Output: ElementType &element - the element bool - SUCCESS or FAIL \*****************************************************************************/ template bool CHashTableType::Get( const KeyType &key, ElementType &element ) const { CHashKey hashKey( key ); return Get( hashKey, element ); } /*****************************************************************************\ Function: CHashTable::Remove Description: Removes an element from the hash table Input: const KeyType &key - the key of the element to remove Output: ElementType &element - the element bool - SUCCESS or FAIL \*****************************************************************************/ template bool CHashTableType::Remove( const KeyType &key, ElementType &element ) { CHashKey hashKey( key ); return Remove( hashKey, element ); } /*****************************************************************************\ Function: CHashTable::Remove Description: Removes an element from the hash table Input: ElementType &element - the element to remove Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CHashTableType::Remove( const ElementType &element ) { // Walk the entire array to find the element const DWORD size = m_HashArray.GetSize(); for( DWORD i = 0; i < size; ++i ) { CHashTableKeyList* pHashKeyList = m_HashArray.GetElement(i); if( pHashKeyList ) { // Search the list for the node with the same element typename CHashTableKeyList::CIterator iterator = pHashKeyList->Begin(); while( iterator != pHashKeyList->End() ) { CHashNode* pHashNode = (*iterator); if( pHashNode->GetElement() == element ) { if( pHashKeyList->Remove( iterator ) ) { DeleteHashNode( pHashNode ); if( pHashKeyList->IsEmpty() ) { m_HashArray.SetElement( i, NULL ); DeleteHashKeyList( pHashKeyList ); } ASSERT( m_Count > 0 ); --m_Count; #ifdef _DEBUG ++m_RemoveCount; #endif return true; } else { ASSERT(0); return false; } } ++iterator; } } } // Element was not found ASSERT(0); return false; } /*****************************************************************************\ Function: CHashTable::Add Description: Adds an element to the hash table Input: const CHashKey &hashKey - the key to which the element is referenced const ElementType &element - the element to be added Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CHashTableType::Add( const CHashKey &hashKey, const ElementType &element ) { if( m_HashArray.GetSize() == 0 ) { return false; } const DWORD index = GetHashIndex( hashKey ); ASSERT( index < m_HashArray.GetSize() ); CHashTableKeyList* pHashKeyList = m_HashArray.GetElement( index ); // Use the hash code to find a linked list containing all keys with the // same hash code if( !pHashKeyList ) { // if the list doesn't exist then create a new one pHashKeyList = CreateHashKeyList(); if( pHashKeyList ) { // Add the new hash key list to hash array if( !m_HashArray.SetElement( index, pHashKeyList ) ) { ASSERT(0); SafeDelete( pHashKeyList ); return false; } } else { ASSERT(0); return false; } } // Create the node to add to the list CHashNode* pHashNode = CreateHashNode( hashKey, element ); if( pHashNode ) { // Add the node to the hash key list if( pHashKeyList->Add( pHashNode ) ) { ++m_Count; #ifdef _DEBUG ++m_AddCount; if( pHashKeyList->GetCount() > 1 ) { ++m_CollisionCount; } #endif return true; } else { DeleteHashNode( pHashNode ); ASSERT(0); return false; } } else { ASSERT(0); return false; } } /*****************************************************************************\ Function: CHashTable::Get Description: Gets the element in the hash table referenced by the key Input: const CHashKey &hashKey - the key of the element to get Output: ElementType &element - the element bool - SUCCESS or FAIL \*****************************************************************************/ template bool CHashTableType::Get( const CHashKey &hashKey, ElementType &element ) const { if( m_HashArray.GetSize() != 0 ) { const DWORD index = GetHashIndex( hashKey ); ASSERT( index < m_HashArray.GetSize() ); CHashTableKeyList* pHashKeyList = m_HashArray.GetElement( index ); if( pHashKeyList ) { // Search the list for the node with the same key typename CHashTableKeyList::CIterator iterator = pHashKeyList->Begin(); while( iterator != pHashKeyList->End() ) { CHashNode* pHashNode = (*iterator); if( pHashNode->GetHashKey() == hashKey ) { element = pHashNode->GetElement(); return true; } ++iterator; } } } return false; } /*****************************************************************************\ Function: CHashTable::Remove Description: Removes an element from the hash table Input: const CHashKey &hashKey - the key of the element to remove Output: ElementType &element - the element bool - SUCCESS or FAIL \*****************************************************************************/ template bool CHashTableType::Remove( const CHashKey &hashKey, ElementType &element ) { if( m_HashArray.GetSize() != 0 ) { const DWORD index = GetHashIndex( hashKey ); ASSERT( index < m_HashArray.GetSize() ); CHashTableKeyList* pHashKeyList = m_HashArray.GetElement( index ); if( pHashKeyList ) { // Search the list for the node with the same key typename CHashTableKeyList::CIterator iterator = pHashKeyList->Begin(); while( iterator != pHashKeyList->End() ) { CHashNode* pHashNode = (*iterator); if( pHashNode->GetHashKey() == hashKey ) { element = pHashNode->GetElement(); if( pHashKeyList->Remove( iterator ) ) { DeleteHashNode( pHashNode ); if( pHashKeyList->IsEmpty() ) { m_HashArray.SetElement( index, NULL ); DeleteHashKeyList( pHashKeyList ); } ASSERT( m_Count > 0 ); --m_Count; #ifdef _DEBUG ++m_RemoveCount; #endif return true; } else { ASSERT(0); return false; } } ++iterator; } } } ASSERT(0); return false; } /*****************************************************************************\ Function: CHashTable::IsEmpty Description: Determines if the hash table is empty Input: void Output: bool \*****************************************************************************/ template bool CHashTableType::IsEmpty( void ) const { return ( m_Count == 0 ); } /*****************************************************************************\ Function: CHashTable::GetCount Description: Returns number of elements. Input: void Output: DWORD \*****************************************************************************/ template DWORD CHashTableType::GetCount( void ) const { return m_Count; } /*****************************************************************************\ Function: CHashTable::DebugPrint Description: Prints the hashtable to std output for debug only Input: none Output: none \*****************************************************************************/ template void CHashTableType::DebugPrint( void ) const { #ifdef _DEBUG DPF( GFXDBG_STDLIB, "%s\n", __FUNCTION__ ); DPF( GFXDBG_STDLIB, "\tAddress = %p\n", this ); DPF( GFXDBG_STDLIB, "\tCount = %u\n", m_Count ); DPF( GFXDBG_STDLIB, "\tAdd Count = %u\n", m_AddCount ); DPF( GFXDBG_STDLIB, "\tRemove Count = %u\n", m_RemoveCount ); DPF( GFXDBG_STDLIB, "\tCollision Count = %u\n", m_CollisionCount ); for( DWORD i = 0; i < m_HashArray.GetSize(); i++ ) { CHashTableKeyList* pHashKeyList = m_HashArray.GetElement(i); if( pHashKeyList ) { DPF( GFXDBG_STDLIB, "\tHashArray.Element[%u].Count = %u\n", i, pHashKeyList->GetCount() ); } else { DPF( GFXDBG_STDLIB, "\tHashArray.Element[%u].Count = 0\n", i ); } } #endif } /*****************************************************************************\ Function: CHashTable::CreateHashKeyList Description: Creates a hashtable key list Input: none Output: CHashTableKeyList* \*****************************************************************************/ template typename CHashTableType::CHashTableKeyList* CHashTableType::CreateHashKeyList( void ) { CHashTableKeyList* pHashKeyList = new CHashTableKeyList(); ASSERT( pHashKeyList ); return pHashKeyList; } /*****************************************************************************\ Function: CHashTable::DeleteHashKeyList Description: Deletes a hashtable key list Input: CHashTableKeyList* pHashKeyList Output: none \*****************************************************************************/ template void CHashTableType::DeleteHashKeyList( CHashTableKeyList* pHashKeyList ) { if( pHashKeyList ) { while( !pHashKeyList->IsEmpty() ) { typename CHashTableKeyList::CIterator iterator = pHashKeyList->Begin(); CHashNode* pHashNode = (*iterator); DeleteHashNode( pHashNode ); pHashKeyList->Remove( iterator ); } iSTD::SafeDelete( pHashKeyList ); } } /*****************************************************************************\ Function: CHashTable::CreateHashNode Description: Creates a hashtable list node Input: const CHashKey &hashKey const ElementType &element Output: CHashNode* \*****************************************************************************/ template typename CHashTableType::CHashNode* CHashTableType::CreateHashNode( const CHashKey &hashKey, const ElementType &element ) { CHashNode* pHashNode = new CHashNode( hashKey, element ); ASSERT( pHashNode ); return pHashNode; } /*****************************************************************************\ Function: CHashTable::DeleteHashNode Description: Deletes a hashtable list node Input: CHashNode* pHashNode Output: none \*****************************************************************************/ template void CHashTableType::DeleteHashNode( CHashNode* pHashNode ) { if( pHashNode ) { iSTD::SafeDelete( pHashNode ); } } /*****************************************************************************\ Function: CHashTable::GetHashSize Description: Determines the size of the hash array Input: const DWORD size - max number of elements in the hash table Output: DWORD \*****************************************************************************/ template DWORD CHashTableType::GetHashSize( const DWORD size ) const { // the size of the hash table array is a large prime number near but // smaller than the maximum size of the cache but not near a power of two if( size >= 6151 ) { return 6151; } else if( size >= 3079 ) { return 3079; } else if( size >= 1543 ) { return 1543; } else if( size >= 769 ) { return 769; } else if( size >= 389 ) { return 389; } else if( size >= 193 ) { return 193; } else if( size >= 97 ) { return 97; } else { return 53; } } /*****************************************************************************\ Function: CHashTable::GetHashIndex Description: Determines the index in the hash array for the hash key Input: const CHashKey &hashKey Output: DWORD \*****************************************************************************/ template DWORD CHashTableType::GetHashIndex( const CHashKey &hashKey ) const { return ( hashKey.GetHashCode() % m_HashArray.GetSize() ); } /*****************************************************************************\ Function: CHashKey constructor Description: Initializes internal data Input: void Output: none \*****************************************************************************/ template CHashTableType::CHashKey::CHashKey( void ) : CObject() { SafeMemSet( &m_KeyValue, 0, sizeof(KeyType) ); m_HashCode = 0; } /*****************************************************************************\ Function: CHashKey constructor Description: Initializes internal data Input: const KeyType &keyValue Output: none \*****************************************************************************/ template CHashTableType::CHashKey::CHashKey( const KeyType &keyValue ) : CObject() { #if defined(_WIN32) && defined(_MSC_VER) ASSERT( IsAligned( &m_KeyValue, sizeof(DQWORD) ) ); ASSERT( IsAligned( &m_HashCode, sizeof(DQWORD) ) ); m_KeyValue = keyValue; ASSERT( m_KeyValue == keyValue ); if( sizeof(KeyType) < sizeof(DQWORD) ) { const DWORD* pKeyValue = (const DWORD*)&m_KeyValue; m_HashCode = *pKeyValue++; const DWORD count = (DWORD)( sizeof(KeyType) / sizeof(DWORD) ); for( DWORD i = 1; i < count; ++i ) { const DWORD data = *pKeyValue++; m_HashCode = ( m_HashCode << 1 ) ^ data; } } else { const DWORD szAlignedKeyValue = (DWORD)( ( ( ( sizeof(KeyType) - 1 ) / sizeof(DQWORD) ) + 1 ) * sizeof(DQWORD) ); const DWORD szPad = szAlignedKeyValue - (DWORD)sizeof(KeyType); // Initialize structure padding due to packing alignment if( szPad ) { SafeMemSet( (BYTE*)&m_KeyValue + sizeof(KeyType), 0, szPad ); } // Generate hash code const __m128i* pKeyValue = (const __m128i*)&m_KeyValue; __m128i hash = _mm_load_si128( pKeyValue++ ); const DWORD count = szAlignedKeyValue / sizeof(DQWORD); for( DWORD i = 1; i < count; ++i ) { const __m128i data = _mm_load_si128( pKeyValue++ ); hash = _mm_xor_si128( _mm_slli_si128( hash, 1 ), data ); } // Combine four 32-bit integers into single 32-bit integer hash = _mm_xor_si128( _mm_unpackhi_epi32( hash, hash ), _mm_unpacklo_epi32( hash, hash ) ); hash = _mm_xor_si128( _mm_shuffle_epi32( hash, 0x2 ), hash ); m_HashCode = _mm_cvtsi128_si32( hash ); } #else // _MSC_VER ASSERT( IsAligned( &m_KeyValue, sizeof(DWORD) ) ); ASSERT( IsAligned( &m_HashCode, sizeof(DWORD) ) ); m_KeyValue = keyValue; ASSERT( m_KeyValue == keyValue ); const DWORD* pKeyValue = (const DWORD*)&m_KeyValue; m_HashCode = *pKeyValue++; const DWORD count = (DWORD)( sizeof(KeyType) / sizeof(DWORD) ); for( DWORD i = 1; i < count; ++i ) { const DWORD data = *pKeyValue++; m_HashCode = ( m_HashCode << 1 ) ^ data; } #endif // _MSC_VER } /*****************************************************************************\ Function: CHashKey constructor Description: Initializes internal data Input: const KeyType &keyValue const DWORD hashCode Output: none \*****************************************************************************/ template CHashTableType::CHashKey::CHashKey( const KeyType &keyValue, const DWORD hashCode ) : CObject() { m_KeyValue = keyValue; ASSERT( m_KeyValue == keyValue ); m_HashCode = hashCode; } /*****************************************************************************\ Function: CHashKey copy constructor Description: Initializes internal data Input: const CHashKey &hashKey Output: none \*****************************************************************************/ template CHashTableType::CHashKey::CHashKey( const CHashKey &hashKey ) { m_KeyValue = hashKey.m_KeyValue; m_HashCode = hashKey.m_HashCode; } /*****************************************************************************\ Function: CHashKey destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template CHashTableType::CHashKey::~CHashKey( void ) { } /*****************************************************************************\ Function: CHashKey::GetHashCode Description: Returns the 32-bit hash code Input: none Output: DWORD \*****************************************************************************/ template DWORD CHashTableType::CHashKey::GetHashCode( void ) const { return m_HashCode; } /*****************************************************************************\ Function: CHashKey::GetKeyValue Description: Returns the key value Input: none Output: const KeyType& \*****************************************************************************/ template const KeyType& CHashTableType::CHashKey::GetKeyValue( void ) const { return m_KeyValue; } /*****************************************************************************\ Function: CHashKey::operator == Description: Determines if the hash keys are equal Input: const CHashKey &hashKey Output: bool - true or false \*****************************************************************************/ template inline bool CHashTableType::CHashKey::operator == ( const CHashKey &hashKey ) const { if( m_HashCode == hashKey.m_HashCode ) { return ( m_KeyValue == hashKey.m_KeyValue ); } else { return false; } } /*****************************************************************************\ Function: CHashNode constructor Description: Initializes internal data Input: const CHashKey &hashKey const ElementType &element Output: none \*****************************************************************************/ template CHashTableType::CHashNode::CHashNode( const CHashKey &hashKey, const ElementType &element ) : CObject(), m_HashKey( hashKey ) { m_Element = element; } /*****************************************************************************\ Function: CHashNode destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template CHashTableType::CHashNode::~CHashNode( void ) { } /*****************************************************************************\ Function: CHashKey::GetHashKey Description: Returns the hash key Input: none Output: const CHashKey& \*****************************************************************************/ template const typename CHashTableType::CHashKey& CHashTableType::CHashNode::GetHashKey( void ) const { return m_HashKey; } /*****************************************************************************\ Function: CHashKey::GetElement Description: Returns the element Input: none Output: ElementType \*****************************************************************************/ template ElementType CHashTableType::CHashNode::GetElement( void ) const { return m_Element; } /*****************************************************************************\ Function: CHashTable::CIterator constructor Description: Default constructor Input: none Output: none \*****************************************************************************/ template CHashTableType::CIterator::CIterator( void ) : m_Iterator() { m_Array = NULL; m_ArrayIndex = 0; } /*****************************************************************************\ Function: CHashTable::CIterator copy constructor Description: Copy constructor Input: none Output: none \*****************************************************************************/ template CHashTableType::CIterator::CIterator( const CIterator &iterator ) : m_Iterator( iterator.m_Iterator ) { m_Array = iterator.m_Array; m_ArrayIndex = iterator.m_ArrayIndex; } /*****************************************************************************\ Function: CHashTable::CIterator operator-- Description: Iterates backwards through the hash table via predecrement Input: none Output: CHashTable::CIterator& - iterator of previous entry \*****************************************************************************/ template typename CHashTableType::CIterator& CHashTableType::CIterator::operator--( void ) { --m_Iterator; CHashTableKeyList* pHashKeyList = m_Array->GetElement( m_ArrayIndex ); ASSERT( pHashKeyList ); while( ( m_Iterator == pHashKeyList->End() ) && ( m_ArrayIndex != 0 ) ) { CHashTableKeyList* pPrevHashKeyList = m_Array->GetElement( --m_ArrayIndex ); if( pPrevHashKeyList ) { pHashKeyList = pPrevHashKeyList; m_Iterator = pHashKeyList->End(); --m_Iterator; } } return *this; } /*****************************************************************************\ Function: CHashTable::CIterator operator++ Description: Iterates forwards through the hash table via preincrement Input: none Output: CHashTable::CIterator& - iterator of next entry \*****************************************************************************/ template typename CHashTableType::CIterator& CHashTableType::CIterator::operator++( void ) { ++m_Iterator; CHashTableKeyList* pHashKeyList = m_Array->GetElement( m_ArrayIndex ); ASSERT( pHashKeyList ); const DWORD maxIndex = m_Array->GetSize() - 1; while( ( m_Iterator == pHashKeyList->End() ) && ( m_ArrayIndex != maxIndex ) ) { CHashTableKeyList* pNextHashKeyList = m_Array->GetElement( ++m_ArrayIndex ); if( pNextHashKeyList ) { pHashKeyList = pNextHashKeyList; m_Iterator = pHashKeyList->Begin(); } } return *this; } /*****************************************************************************\ Function: CHashTable::CIterator::operator== Description: Determines if the iterators are equal Input: const CIterator& - pointer to the iterator to compare to. Output: bool - true if this iterator and the passed-in iterator point to the same hash table node. \*****************************************************************************/ template bool CHashTableType::CIterator::operator==( const CIterator& iterator ) const { return m_Iterator == iterator.m_Iterator; } /*****************************************************************************\ Function: CHashTable::CIterator::operator!= Description: Determines if the iterators are not equal Input: const CIterator& - pointer to the iterator to compare to. Output: bool - true if this iterator and the passed-in iterator point to different hash table nodes. \*****************************************************************************/ template bool CHashTableType::CIterator::operator!=( const CIterator& iterator ) const { return m_Iterator != iterator.m_Iterator; } /*****************************************************************************\ Function: CHashTable::CIterator::operator= Description: Sets the iterators equal Input: const CIterator& - reference to the iterator to copy from. Output: const CIterator & - reference to self \*****************************************************************************/ template typename CHashTableType::CIterator& CHashTableType::CIterator::operator=( const CIterator &iterator ) { m_Array = iterator.m_Array; m_ArrayIndex = iterator.m_ArrayIndex; m_Iterator = iterator.m_Iterator; return *this; } /*****************************************************************************\ Function: CHashTable::CIterator::operator* Description: Returns a reference to the element that this iterator points to Input: none Output: ElementType \*****************************************************************************/ template ElementType CHashTableType::CIterator::operator*( void ) { return (*m_Iterator)->GetElement(); } /*****************************************************************************\ Function: CHashTable::CIterator::GetKey() Description: Returns key value. Input: none Output: KeyType \*****************************************************************************/ template const KeyType& CHashTableType::CIterator::GetKeyValue( void ) { return (*m_Iterator)->GetHashKey().GetKeyValue(); } /*****************************************************************************\ Function: CHashTable::Begin Description: Returns an iterator to the first node in the hash table. Input: none Output: CHashTable::CIterator \*****************************************************************************/ template typename CHashTableType::CIterator CHashTableType::Begin( void ) const { CIterator iterator; const DWORD size = m_HashArray.GetSize(); for( DWORD i = 0; i < size; ++i ) { CHashTableKeyList* pHashKeyList = m_HashArray.GetElement(i); if( pHashKeyList ) { iterator.m_Iterator = pHashKeyList->Begin(); iterator.m_Array = const_cast(&m_HashArray); iterator.m_ArrayIndex = i; return iterator; } } return iterator; } /*****************************************************************************\ Function: CHashTable::End Description: Returns an iterator to the last (dummy) node in the hash table Input: none Output: CHashTable::CIterator \*****************************************************************************/ template typename CHashTableType::CIterator CHashTableType::End( void ) const { CIterator iterator; const DWORD size = m_HashArray.GetSize(); for( int i = (int)size-1; i >= 0; --i ) { CHashTableKeyList* pHashKeyList = m_HashArray.GetElement((DWORD)i); if( pHashKeyList ) { iterator.m_Iterator = pHashKeyList->End(); iterator.m_Array = const_cast(&m_HashArray); iterator.m_ArrayIndex = (DWORD)i; return iterator; } } return iterator; } /*****************************************************************************\ Function: CHashTable::Add Description: Adds the element to the hash table and returns its iterator Input: const CHashKey &hashKey const ElementType &element Output: CIterator &iterator bool - true if element was added \*****************************************************************************/ template bool CHashTableType::Add( const CHashKey &hashKey, const ElementType &element, CIterator &iterator ) { if( m_HashArray.GetSize() == 0 ) { return false; } const DWORD index = GetHashIndex( hashKey ); ASSERT( index < m_HashArray.GetSize() ); CHashTableKeyList* pHashKeyList = m_HashArray.GetElement( index ); // Use the hash code to find a linked list containing all keys with the // same hash code if( !pHashKeyList ) { // if the list doesn't exist then create a new one pHashKeyList = CreateHashKeyList(); if( pHashKeyList ) { // Add the new hash key list to hash array if( !m_HashArray.SetElement( index, pHashKeyList ) ) { ASSERT(0); SafeDelete( pHashKeyList ); return false; } } else { ASSERT(0); return false; } } // Create the node to add to the list CHashNode* pHashNode = CreateHashNode( hashKey, element ); if( pHashNode ) { // Add the node to the hash key list if( pHashKeyList->Add( pHashNode ) ) { ++m_Count; #ifdef _DEBUG ++m_AddCount; if( pHashKeyList->GetCount() > 1 ) { ++m_CollisionCount; } #endif iterator.m_Array = &m_HashArray; iterator.m_ArrayIndex = index; iterator.m_Iterator = pHashKeyList->Begin(); return true; } else { DeleteHashNode( pHashNode ); ASSERT(0); return false; } } else { ASSERT(0); return false; } } /*****************************************************************************\ Function: CHashTable::Get Description: Gets the iterator of the element from the hash table Input: const CHashKey &hashKey Output: CIterator &iterator bool - true if element was removed \*****************************************************************************/ template bool CHashTableType::Get( const CHashKey &hashKey, CIterator &iterator ) const { if( m_HashArray.GetSize() != 0 ) { const DWORD index = GetHashIndex( hashKey ); ASSERT( index < m_HashArray.GetSize() ); CHashTableKeyList* pHashKeyList = m_HashArray.GetElement( index ); if( pHashKeyList ) { // Search the list for the node with the same key typename CHashTableKeyList::CIterator list_iterator = pHashKeyList->Begin(); while( list_iterator != pHashKeyList->End() ) { CHashNode* pHashNode = (*list_iterator); if( pHashNode->GetHashKey() == hashKey ) { iterator.m_Array = const_cast(&m_HashArray); iterator.m_ArrayIndex = index; iterator.m_Iterator = list_iterator; return true; } ++list_iterator; } } } return false; } /*****************************************************************************\ Function: CHashTable::Remove Description: Removes element from the hash table via iterator Input: CIterator iterator Output: bool - true if element was removed \*****************************************************************************/ template bool CHashTableType::Remove( CIterator iterator ) { CHashTableKeyList* pHashKeyList = m_HashArray. GetElement( iterator.m_ArrayIndex ); if( pHashKeyList ) { CHashNode* pHashNode = *(iterator.m_Iterator); pHashKeyList->Remove( iterator.m_Iterator ); DeleteHashNode( pHashNode ); if( pHashKeyList->IsEmpty() ) { m_HashArray.SetElement( iterator.m_ArrayIndex, NULL ); DeleteHashKeyList( pHashKeyList ); } ASSERT( m_Count > 0 ); --m_Count; #ifdef _DEBUG ++m_RemoveCount; #endif return true; } return false; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/LRUSet.h000066400000000000000000000424651363533017100236670ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include namespace iSTD { #define LRUTemplateList class KeyType, class ValueType, class CAllocatorType #define LRUClassType CLRUSet /****************************************************************************** Class: CLRUSet Description: Maintains a linked list of the elements in the set. The structure maintains a pointer to the newest item (most recently touched) and the oldest item (first to be evicted if needed) items. When traversing the list the pointers go from the oldest towards the newest. More details can be found in the file description above. ******************************************************************************/ template class CLRUSet : public CObject { public: /************************************************************************** Struct: SLRUSetItem Description: The container for a key-value-pair to be stored in the LRU. This is a linked list node. **************************************************************************/ struct SLRUSetItem : public CObject { SLRUSetItem *pNextItem, *pPreviousItem; KeyType key; ValueType value; }; class CLRUSetIterator { friend class CLRUSet; public: //always use HasNext() before calling Next(). Next has side effects //so you only call it once to get the value, the next call to Next() //must be preceded by a check of HasNext() otherwise you will //eventually dereference NULL. bool HasNext() const; const ValueType& Next(); private: CLRUSetIterator() {} SLRUSetItem* current; }; CLRUSet(); CLRUSet(short in_setSize, SLRUSetItem* in_itemArrayLocation); ~CLRUSet(); void Initialize(short in_setSize, SLRUSetItem* in_itemArrayLocation); bool IsItemInSet(const KeyType& in_key) const; bool IsItemInSet(const KeyType& in_key, ValueType& out_value) const; bool TouchItem(const KeyType& touch_key, const ValueType& touch_value); bool TouchItem(const KeyType& touch_key, const ValueType& touch_value, KeyType& evict_key, ValueType& evict_value); short GetOccupancy() const; CLRUSetIterator* InitAndReturnIterator(); protected: bool EvictAndAdd(const KeyType& newKey, const ValueType& newValue); void MakeMRU(SLRUSetItem* touchedItem); SLRUSetItem *m_pNewestItem, *m_pOldestItem; SLRUSetItem *m_aItemArray; short m_count, m_setSize; CLRUSetIterator m_iterator; }; /*****************************************************************************\ Function: CLRUSet() Description: Initializes values. The set depends on the count value to indicate that the unitialized values in m_aItemArray are not actual elements. Input: none Output: none \*****************************************************************************/ template LRUClassType::CLRUSet() : CObject(), m_setSize(1), m_count(0) { m_pOldestItem = NULL; m_pNewestItem = NULL; } /*****************************************************************************\ Function: CLRUSet() Description: Initializes values. The set depends on the count value to indicate that the unitialized values in m_aItemArray are not actual elements. Input: short in_setSize - number of elements in the set. SLRUSetItem *in_itemArrayLocation - pointer to the space for the linked list nodes. Output: none \*****************************************************************************/ template LRUClassType::CLRUSet( short in_setSize, SLRUSetItem *in_itemArrayLocation) : m_count(0), m_setSize(in_setSize), m_aItemArray(in_itemArrayLocation) { if(m_setSize < 1) { m_setSize = 1; } m_pOldestItem = NULL; m_pNewestItem = NULL; } /*****************************************************************************\ Function: ~CLRUSet() Description: No items are allocated during runtime. Input: none Output: none \*****************************************************************************/ template LRUClassType::~CLRUSet() { //no work required } /*****************************************************************************\ Function: Initialize() Description: Sets the value of the size for the set. Input: short in_setSize - number of elements in the set. SLRUSetItem *in_itemArrayLocation - pointer to the space for the linked list nodes. Output: none \*****************************************************************************/ template void LRUClassType::Initialize( short in_setSize, SLRUSetItem *in_itemArrayLocation) { CLRUSet(in_setSize, in_itemArrayLocation); } /*****************************************************************************\ Function: IsItemInSet() Description: Tests for the existance of an item in the set. This overloaded version is used only for testing existance, see the other overloaded version for retrieval of values. Input: KeyType in_key - The key value to search for. Output: bool - true or false for the existance of the key in the set. \*****************************************************************************/ template bool LRUClassType::IsItemInSet(const KeyType& in_key) const { SLRUSetItem* currentItem = m_pNewestItem; while(NULL != currentItem) { if(currentItem->key == in_key) return true; currentItem = currentItem->pPreviousItem; } return false; } /*****************************************************************************\ Function: IsItemInSet() Description: Tests for the existance of an item in the set. This overloaded version is used for retrieval of values. See the other overloaded version for simple tests of existance in the set. If the return value is false (key not found) then the out_value is unchanged. Input: KeyType in_key - The key value to search for. ValueType& out_value - returns the value associated with the key, if the key was found. If the key was not found then this value is not set and the return is false. Output: bool - true or false for the existance of the key in the set. \*****************************************************************************/ template bool LRUClassType::IsItemInSet( const KeyType& in_key, ValueType& out_value) const { SLRUSetItem* currentItem = m_pNewestItem; while(NULL != currentItem) { if(currentItem->key == in_key) { out_value = currentItem->value; return true; } currentItem = currentItem->pPreviousItem; } return false; } /*****************************************************************************\ Function: TouchItem() Description: Moves the specified item to the most-recently-used position. If the item is in the set then the items are re-ordered to make MRU, if the item is not in the set then the least-recently-used item in the set is evicted and the new item is added to the set. Input: KeyType touch_key - The key value to search for. ValueType touch_value - the associated value stored with the key. Output: bool - true/false if an item was evicted to make room \*****************************************************************************/ template bool LRUClassType::TouchItem( const KeyType& touch_key, const ValueType& touch_value) { SLRUSetItem* currentItem = m_pNewestItem; while(currentItem) { //found the key in the list, no evict required if(currentItem->key == touch_key) { MakeMRU(currentItem); return false; } currentItem = currentItem->pPreviousItem; } //couldn't find the key in the list, evict the LRU and add the new key+value bool wasItemEvicted = EvictAndAdd(touch_key, touch_value); return wasItemEvicted; } /*****************************************************************************\ Function: TouchItem() Description: Moves the specified item to the most-recently-used position. If the item is in the set then the items are re-ordered to make MRU, if the item is not in the set then the least-recently-used item in the set is evicted and the new item is added to the set. If an item is not evicted then the value of evict_key and evict_value are not changed. Input: KeyType touch_key - The key value to search for. ValueType touch_value - the associated value stored with the key. KeyType& evict_key - if return is true, then this value is that of the key which was evicted to add the touch_key to the set. ValueType& evict_value - if return is true, then this value is that of the value which was evicted to add the touch_value to the set. Output: bool - true/false if an item was evicted to make room \*****************************************************************************/ template bool LRUClassType::TouchItem( const KeyType& touch_key, const ValueType& touch_value, KeyType& evict_key, ValueType& evict_value) { SLRUSetItem* currentItem = m_pNewestItem; while(currentItem) { //found the key in the list, no evict required if(currentItem->key == touch_key) { MakeMRU(currentItem); return false; } currentItem = currentItem->pPreviousItem; } //couldn't find the key in the list, evict the LRU and add the new key+value //and return the evicted item. if m_count is not up to m_setSize yet this //means an uninitialized value is going to be evicted, don't want to tell //the user about it. if(m_count == m_setSize) { evict_key = m_pOldestItem->key; evict_value = m_pOldestItem->value; } bool wasItemEvicted = EvictAndAdd(touch_key, touch_value); return wasItemEvicted; } /*****************************************************************************\ Function: EvictAndAdd() Description: Protected function. Used after determining that an item touched is not in the set, causes the eviction of the least-recently-used item and adds the new item into the set at the most-recently-used position. In the case when the set is not full the new item is added without an eviction. This function has no intelligence for searching, it is unsafe to not search for the element to be added first. Input: KeyType newKey - the key value to add. ValueType newValue - the associated value to add. Output: none \*****************************************************************************/ template bool LRUClassType::EvictAndAdd( const KeyType& newKey, const ValueType& newValue) { //this is the first item added to the set, need to initialize the newest //and oldest item pointers. if(m_count == 0) { SLRUSetItem* newItem = &m_aItemArray[0]; newItem->key = newKey; newItem->value = newValue; newItem->pNextItem = NULL; newItem->pPreviousItem = NULL; m_pNewestItem = newItem; m_pOldestItem = newItem; m_count++; return false; } //if the number of items stored is less than the capacity then don't evict //an element, instead insert it and push out the m_pNewestItem. else if(m_count < m_setSize) { SLRUSetItem* newItem = &m_aItemArray[m_count]; newItem->key = newKey; newItem->value = newValue; newItem->pNextItem = NULL; newItem->pPreviousItem = m_pNewestItem; m_pNewestItem->pNextItem = newItem; m_pNewestItem = newItem; m_count++; return false; } else //normal operation, evict the oldest and add the new item. { //this will become the LRU after this code finishes evicting the oldest SLRUSetItem* newOldest = m_pOldestItem->pNextItem; //the new item being inserted into the set, it will be the MRU SLRUSetItem* newNewest = m_pOldestItem; //is currently the MRU, will be the second most recently used when finished SLRUSetItem* oldNewest = m_pNewestItem; //at this point the oldest is going to be evicted but in it's place the //newest will be stored. newNewest->key = newKey; newNewest->value = newValue; newNewest->pNextItem = NULL; newNewest->pPreviousItem = oldNewest; //the second MRU points to the new first MRU oldNewest->pNextItem = newNewest; //the new LRU becomes the tail and NULLs it's previous pointer newOldest->pPreviousItem = NULL; m_pNewestItem = newNewest; m_pOldestItem = newOldest; return true; } } /*****************************************************************************\ Function: MakeMRU() Description: Protected function. Used after determining that an item touched is in the set, causes the touched item to be moved into the most-recently used position. Input: SLRUSetItem* touchedItem: The linked list element to be moved to the MRU position. Output: none \*****************************************************************************/ template void LRUClassType::MakeMRU(SLRUSetItem* touchedItem) { //touched item is MRU if(m_pNewestItem == touchedItem) return; //if there is a previous item then this is not the oldest item, hook //the previous item to the next if(touchedItem->pPreviousItem != NULL) { touchedItem->pPreviousItem->pNextItem = touchedItem->pNextItem; touchedItem->pNextItem->pPreviousItem = touchedItem->pPreviousItem; } else { m_pOldestItem = touchedItem->pNextItem; m_pOldestItem->pPreviousItem = NULL; } //always place the most recently used at "end" of the linked list m_pNewestItem->pNextItem = touchedItem; touchedItem->pNextItem = NULL; touchedItem->pPreviousItem = m_pNewestItem; m_pNewestItem = touchedItem; } /*****************************************************************************\ Function: GetOccupancy() Description: Returns the number of keys in the set Input: none Output: short - The number of keys in the set. \*****************************************************************************/ template short LRUClassType::GetOccupancy() const { return m_count; } /*****************************************************************************\ Function: InitAndReturnIterator() Description: Returns a pointer to the singleton iterator for the class. Do not attempt to free the memory for this pointer. Input: none Output: return CLRUSetIterator* - a pointer to the iterator, do not free this pointer. \*****************************************************************************/ template typename LRUClassType::CLRUSetIterator* LRUClassType::InitAndReturnIterator() { m_iterator.current = m_pNewestItem; return &m_iterator; } /*****************************************************************************\ Function: HasNext() Description: Indicates if it is safe to call Next() on the iterator. when HasNext() is false there are no more items to iterate. Input: none Output: bool - true if it is safe to use Next(), false if the iterator is finished. \*****************************************************************************/ template bool LRUClassType::CLRUSetIterator::HasNext() const { return (NULL != current) ? true : false; } /*****************************************************************************\ Function: Next() Description: Returns the value stored at the current iterator position. This function is unsafe if Next() returns NULL. Input: none Output: ValueType - the value stored at the current iterator position. \*****************************************************************************/ template const ValueType& LRUClassType::CLRUSetIterator::Next() { ValueType& val = current->value; current = current->pNextItem; return val; } }; //namespace iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/LinearAllocator.h000066400000000000000000000253741363533017100256240ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #include "Threading.h" namespace iSTD { /*****************************************************************************\ Class: CLinearAllocator Description: Manages a memory buffer via linear allocation \*****************************************************************************/ template class CLinearAllocator : public CObject { public: CLinearAllocator( void* pBaseAddress, const DWORD size ); virtual ~CLinearAllocator( void ); DWORD GetAvailableSpace( void ) const; DWORD GetUsedSpace( void ) const; void* GetSpace( const DWORD size ); void* GetSpaceAligned( const DWORD size, const DWORD alignSize ); bool IsEmpty( void ) const; bool IsFull( void ) const; void Align( const DWORD alignSize ); void PutSpace( const DWORD size ); void PutAllSpace( void ); void* ReserveSpace( const DWORD size ); virtual void Resize( const DWORD size ); protected: void* m_pBaseAddress; DWORD m_Size; // Total size of memory DWORD m_SizeUsed; // Size of used memory DWORD m_SizeReserved; // Size of reserved memory DECL_DEBUG_MUTEX( m_InstanceNotThreadSafe ) }; /*****************************************************************************\ Function: CLinearAllocator Constructor Description: Initializes internal data Input: void* pBaseAddress const DWORD size Output: none \*****************************************************************************/ template inline CLinearAllocator::CLinearAllocator( void* pBaseAddress, const DWORD size ) : CObject() { m_pBaseAddress = pBaseAddress; m_Size = size; m_SizeUsed = 0; m_SizeReserved = 0; INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinearAllocator Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template inline CLinearAllocator::~CLinearAllocator( void ) { DELETE_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinearAllocator::GetAvailableSpace Description: Gets the amount of space available in the buffer Input: none Output: DWORD - size in bytes \*****************************************************************************/ template inline DWORD CLinearAllocator::GetAvailableSpace( void ) const { const DWORD size = m_Size - GetUsedSpace(); return size; } /*****************************************************************************\ Function: CLinearAllocator::GetUsedSpace Description: Gets the amount of space used in the buffer Input: none Output: DWORD - size in bytes \*****************************************************************************/ template inline DWORD CLinearAllocator::GetUsedSpace( void ) const { const DWORD size = m_SizeUsed + m_SizeReserved; return size; } /*****************************************************************************\ Function: CLinearAllocator::GetSpace Description: Gets space from the top of the buffer Input: const DWORD size - size in bytes Output: void* - linear address of space \*****************************************************************************/ template inline void* CLinearAllocator::GetSpace( const DWORD size ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); void* pAddress = NULL; if( GetAvailableSpace() >= size ) { pAddress = (BYTE*)m_pBaseAddress + m_SizeUsed; m_SizeUsed += size; } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return pAddress; } /*****************************************************************************\ Function: CLinearAllocator::GetSpaceAligned Description: Gets space from the top of the buffer Input: const DWORD size - size in bytes const DWORD alignSize - alignment in bytes Output: void* - linear address of space \*****************************************************************************/ template inline void* CLinearAllocator::GetSpaceAligned( const DWORD size, const DWORD alignSize ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); void* pAddress = NULL; if( GetAvailableSpace() >= size ) { // Determine the number of bytes required to // align the allocation const DWORD offset = GetAlignmentOffset( (BYTE*)m_pBaseAddress + m_SizeUsed, alignSize ); if( offset ) { if( ( GetAvailableSpace() >= offset ) && ( GetAvailableSpace() >= offset + size ) ) { pAddress = (BYTE*)m_pBaseAddress + m_SizeUsed + offset; m_SizeUsed += size + offset; } } else { pAddress = (BYTE*)m_pBaseAddress + m_SizeUsed; m_SizeUsed += size; } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return pAddress; } /*****************************************************************************\ Function: CLinearAllocator::IsEmpty Description: Determines if the buffer is empty Input: void Output: bool \*****************************************************************************/ template inline bool CLinearAllocator::IsEmpty( void ) const { const bool isEmpty = ( m_SizeUsed == 0 ) && ( m_SizeReserved == 0 ); return isEmpty; } /*****************************************************************************\ Function: CLinearAllocator::IsFull Description: Determines if the buffer is full Input: void Output: bool \*****************************************************************************/ template inline bool CLinearAllocator::IsFull( void ) const { const bool isFull = ( GetAvailableSpace() == 0 ); return isFull; } /*****************************************************************************\ Function: CLinearAllocator::Align Description: Aligns the buffer and pads with zeros Input: const DWORD alignSize - alignment in bytes Output: void \*****************************************************************************/ template inline void CLinearAllocator::Align( const DWORD alignSize ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); const DWORD offset = GetAlignmentOffset( (BYTE*)m_pBaseAddress + m_SizeUsed, alignSize ); if( offset ) { if( m_Size >= m_SizeUsed + offset ) { m_SizeUsed += offset; } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinearAllocator::PutSpace Description: Puts space back at the top of the buffer Input: const DWORD size - size in bytes Output: none \*****************************************************************************/ template inline void CLinearAllocator::PutSpace( const DWORD size ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); m_SizeUsed -= size; RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinearAllocator::PutAllSpace Description: Puts all space back Input: none Output: none \*****************************************************************************/ template inline void CLinearAllocator::PutAllSpace( void ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); m_SizeUsed = 0; m_SizeReserved = 0; RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinearAllocator::ReserveSpace Description: Reserves space at the bottom of the buffer Input: const DWORD size - size in bytes Output: void* - linear address of reserved space \*****************************************************************************/ template inline void* CLinearAllocator::ReserveSpace( const DWORD size ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); void* pAddress = NULL; if( GetAvailableSpace() >= size ) { pAddress = (BYTE*)m_pBaseAddress + m_Size - ( m_SizeReserved + size ); m_SizeReserved += size; } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return pAddress; } /*****************************************************************************\ Function: CLinearAllocator::Resize Description: Changes the size of the buffer Input: const DWORD size - size in bytes Output: none \*****************************************************************************/ template void CLinearAllocator::Resize( const DWORD size ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); m_Size = size; RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/LinearStack.h000066400000000000000000000174431363533017100247470ustar00rootroot00000000000000 /*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Array.h" namespace iSTD { /*****************************************************************************\ Struct: IsLinearStackTypeSupported \*****************************************************************************/ template struct IsLinearStackTypeSupported { enum { value = false }; }; template<> struct IsLinearStackTypeSupported { enum { value = true }; }; template<> struct IsLinearStackTypeSupported { enum { value = true }; }; template<> struct IsLinearStackTypeSupported { enum { value = true }; }; template<> struct IsLinearStackTypeSupported { enum { value = true }; }; template<> struct IsLinearStackTypeSupported { enum { value = true }; }; #ifndef __LP64__ // u/long on linux64 platform is 64-bit type and collides with U/INT64 template<> struct IsLinearStackTypeSupported { enum { value = true }; }; template<> struct IsLinearStackTypeSupported { enum { value = true }; }; #endif template<> struct IsLinearStackTypeSupported { enum { value = true }; }; template<> struct IsLinearStackTypeSupported { enum { value = true }; }; template<> struct IsLinearStackTypeSupported { enum { value = true }; }; template struct IsLinearStackTypeSupported { enum { value = true }; }; /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define LinearStackTemplateList class Type, class CAllocatorType #define CLinearStackType CLinearStack /*****************************************************************************\ Class: CLinearStack Description: Implements an array-based stack \*****************************************************************************/ template class CLinearStack : public CObject { public: CLinearStack( const DWORD size ); virtual ~CLinearStack( void ); bool IsEmpty( void ) const; DWORD GetCount( void ) const; bool Push( const Type element ); Type Pop( void ); Type Top( void ) const; void Reset( void ); void DebugPrint( void ) const; protected: CDynamicArray m_ElementArray; DWORD m_Count; }; /*****************************************************************************\ Function: CLinearStack Constructor Description: Initializes internal data Input: const DWORD size - initial size of the stack Output: none \*****************************************************************************/ template CLinearStackType::CLinearStack( const DWORD size ) : CObject(), m_ElementArray( size ) { m_Count = 0; } /*****************************************************************************\ Function: CLinearStack Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template CLinearStackType::~CLinearStack( void ) { } /*****************************************************************************\ Function: CLinearStack::IsEmpty Description: Returns if the stack is empty Input: none Output: bool - true or false \*****************************************************************************/ template bool CLinearStackType::IsEmpty( void ) const { return m_Count == 0; } /*****************************************************************************\ Function: CLinearStack::GetCount Description: Returns the number of elements in the stack Input: none Output: DWORD - number of elements \*****************************************************************************/ template DWORD CLinearStackType::GetCount( void ) const { return m_Count; } /*****************************************************************************\ Function: CLinearStack::Push Description: Pushes an element on the stack Input: const Type element Output: bool - success or fail \*****************************************************************************/ template bool CLinearStackType::Push( const Type element ) { // Add element to the end of list return m_ElementArray.SetElement( m_Count++, element ); } /*****************************************************************************\ Function: CLinearStack::Pop Description: Pops an element off the stack Input: none Output: Type - element \*****************************************************************************/ template Type CLinearStackType::Pop( void ) { Type element = (Type)0; if( IsEmpty() ) { ASSERT(0); } else { // Get the last element on the list and // remove the last element element = m_ElementArray.GetElement( --m_Count ); } return element; } /*****************************************************************************\ Function: CLinearStack::Top Description: Returns the top element of the stack Input: none Output: Type - element \*****************************************************************************/ template Type CLinearStackType::Top( void ) const { Type element = (Type)0; if( IsEmpty() ) { ASSERT(0); } else { // Get the last element on the list element = m_ElementArray.GetElement( m_Count-1 ); } return element; } /*****************************************************************************\ Function: CLinearStack::Reset Description: Resets the stack Input: none Output: none \*****************************************************************************/ template void CLinearStackType::Reset( void ) { m_Count = 0; } /*****************************************************************************\ Function: CLinearStack::DebugPrint Description: Prints the stack to std output for debug only Input: none Output: none \*****************************************************************************/ template void CLinearStackType::DebugPrint( void ) const { #ifdef _DEBUG m_ElementArray.DebugPrint(); #endif } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/LinkedList.h000066400000000000000000001321711363533017100246050ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #include "Threading.h" #include "MemCopy.h" #if defined _DEBUG # if defined( ISTDLIB_UMD ) && !defined( NO_RTTI ) # include # define TYPEID_NAME( type ) (typeid(type).name()) # else // ISTDLIB_UMD # define TYPEID_NAME( type ) (#type) # endif // ISTDLIB_UMD #else // _DEBUG # define TYPEID_NAME( type ) #endif // _DEBUG namespace iSTD { /*****************************************************************************\ Struct: IsLinkedListTypeSupported \*****************************************************************************/ template struct IsLinkedListTypeSupported { enum { value = false }; }; template<> struct IsLinkedListTypeSupported { enum { value = true }; }; template<> struct IsLinkedListTypeSupported { enum { value = true }; }; template<> struct IsLinkedListTypeSupported { enum { value = true }; }; template<> struct IsLinkedListTypeSupported { enum { value = true }; }; template<> struct IsLinkedListTypeSupported { enum { value = true }; }; #ifndef __LP64__ // u/long on linux64 platform is 64-bit type and collides with U/INT64 template<> struct IsLinkedListTypeSupported { enum { value = true }; }; template<> struct IsLinkedListTypeSupported { enum { value = true }; }; #endif template<> struct IsLinkedListTypeSupported { enum { value = true }; }; template<> struct IsLinkedListTypeSupported { enum { value = true }; }; template<> struct IsLinkedListTypeSupported { enum { value = true }; }; template struct IsLinkedListTypeSupported { enum { value = true }; }; /*****************************************************************************\ Struct: AreLinkedListDuplicatesSupported \*****************************************************************************/ template struct AreLinkedListDuplicatesSupported { enum { value = true }; }; template struct AreLinkedListDuplicatesSupported { enum { value = false }; }; template struct AreLinkedListDuplicatesSupported { enum { value = false }; }; /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define LinkedListTemplateList class Type, class CAllocatorType #define CLinkedListType CLinkedList /*****************************************************************************\ Class: CLinkedList Description: Implements a pointer-based linked-list \*****************************************************************************/ template class CLinkedList : public CObject { protected: class CNode : public CObject { public: CNode( void ); CNode( const Type &element ); virtual ~CNode( void ); void Insert( CNode* pNext ); void Remove( void ); void SetElement( const Type &element ); Type& GetElement( void ); const Type& GetElement( void ) const; void SetPrevious( CNode* pNode ); void SetNext( CNode* pNode ); CNode* GetPrevious( void ) const; CNode* GetNext( void ) const; protected: Type m_Element; CNode* m_Next; CNode* m_Previous; }; public: CLinkedList( void ); virtual ~CLinkedList( void ); class CIterator { public: CIterator( void ); CIterator( CNode* ptr ); CIterator( const CIterator &iterator ); CIterator& operator--( void ); CIterator& operator++( void ); bool operator==( const CIterator &iterator ) const; bool operator!=( const CIterator &iterator ) const; CIterator &operator=( const CIterator &iterator ); Type& operator*( void ); bool IsNull( void ) const; void SetNull( void ); friend class CLinkedList; friend class CConstIterator; protected: CNode* m_Ptr; }; class CConstIterator { public: CConstIterator( void ); CConstIterator( const CIterator &iterator ); CConstIterator( const CNode* ptr ); CConstIterator& operator--( void ); CConstIterator& operator++( void ); bool operator==( const CConstIterator &iterator ) const; bool operator!=( const CConstIterator &iterator ) const; const Type& operator*( void ); bool IsNull( void ) const; void SetNull( void ); friend class CLinkedList; protected: const CNode* m_Ptr; }; bool IsEmpty( void ) const; DWORD GetCount( void ) const; CLinkedListType& operator= ( const CLinkedListType &llist ); CIterator Begin( void ); CIterator Get( const DWORD index ); CIterator End( void ); CConstIterator Begin( void ) const; CConstIterator Get( const DWORD index ) const; CConstIterator End( void ) const; CIterator Find( const Type &element ); CConstIterator Find( const Type &element ) const; bool Add( const Type &element ); bool Remove( const Type &element ); bool Add( const CIterator &location, const Type &element ); bool Remove( const CIterator &location ); void Clear( void ); void Splice( const CIterator &dstLocation, const CIterator &srcLocation, CLinkedListType &srcList ); void SpliceListPartAtTheEnd( CLinkedListType &srcList, const CIterator &srcStartLocation, const CIterator &srcEndLocation ); void Set( const CIterator &location, const Type &element ); void DeleteFreePool( void ); void DebugPrint( void ) const; C_ASSERT( IsLinkedListTypeSupported::value == true ); protected: bool Remove( CNode* &pNode ); CNode* CreateNode( const Type &element ); void DeleteNode( CNode* &pNode ); CNode m_DummyTail; DWORD m_Count; CNode m_FreePoolDummyTail; DWORD m_FreePoolCount; DECL_DEBUG_MUTEX( m_InstanceNotThreadSafe ) }; /*****************************************************************************\ Function: CNode Constructor Description: Initializes internal data Input: none Output: none \*****************************************************************************/ template CLinkedListType::CNode::CNode( void ) : CObject() { SafeMemSet( &m_Element, 0, sizeof(Type) ); m_Next = this; m_Previous = this; } /*****************************************************************************\ Function: CNode Constructor Description: Initializes internal data Input: none Output: none \*****************************************************************************/ template CLinkedListType::CNode::CNode( const Type &element ) : CObject() { m_Element = element; m_Next = this; m_Previous = this; } /*****************************************************************************\ Function: CNode Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template CLinkedListType::CNode::~CNode( void ) { ASSERT( m_Next == this ); ASSERT( m_Previous == this ); } /*****************************************************************************\ Function: CNode::Insert Description: Inserts the node before the given node Input: const CNode* pNext Output: none \*****************************************************************************/ template void CLinkedListType::CNode::Insert( CNode* pNext ) { m_Next = pNext; m_Previous = m_Next->m_Previous; m_Previous->m_Next = this; m_Next->m_Previous = this; } /*****************************************************************************\ Function: CNode::Remove Description: Removes the node from the linked list Input: none Output: none \*****************************************************************************/ template void CLinkedListType::CNode::Remove( void ) { m_Previous->m_Next = m_Next; m_Next->m_Previous = m_Previous; m_Previous = this; m_Next = this; SafeMemSet( &m_Element, 0, sizeof(Type) ); } /*****************************************************************************\ Function: CNode::SetElement Description: Sets the element of the node from the linked list Input: const Type &element Output: none \*****************************************************************************/ template void CLinkedListType::CNode::SetElement( const Type &element ) { m_Element = element; } /*****************************************************************************\ Function: CNode::GetElement Description: Gets the element of the node from the linked list Input: none Output: Type& \*****************************************************************************/ template Type& CLinkedListType::CNode::GetElement( void ) { return m_Element; } /*****************************************************************************\ Function: CNode::GetElement Description: Gets the element of the node from the linked list Input: none Output: const Type& \*****************************************************************************/ template const Type& CLinkedListType::CNode::GetElement( void ) const { return m_Element; } /*****************************************************************************\ Function: CNode::SetPrevious Description: Sets the previous pointer of the node from the linked list Input: CNode* pNode Output: none \*****************************************************************************/ template void CLinkedListType::CNode::SetPrevious( CNode* pNode ) { m_Previous = pNode; } /*****************************************************************************\ Function: CNode::SetNext Description: Sets the next pointer of the node from the linked list Input: CNode* pNode Output: none \*****************************************************************************/ template void CLinkedListType::CNode::SetNext( CNode* pNode ) { m_Next = pNode; } /*****************************************************************************\ Function: CNode::GetPrevious Description: Gets the previous pointer of the node from the linked list Input: none Output: CNode* \*****************************************************************************/ template typename CLinkedListType::CNode* CLinkedListType::CNode::GetPrevious( void ) const { return m_Previous; } /*****************************************************************************\ Function: CNode::GetNext Description: Gets the next pointer of the node from the linked list Input: none Output: CNode* \*****************************************************************************/ template typename CLinkedListType::CNode* CLinkedListType::CNode::GetNext( void ) const { return m_Next; } /*****************************************************************************\ Function: CLinkedList Constructor Description: Initializes internal data Input: none Output: none \*****************************************************************************/ template CLinkedListType::CLinkedList( void ) : CObject() { m_Count = 0; m_FreePoolCount = 0; m_DummyTail.SetNext( &m_DummyTail ); m_DummyTail.SetPrevious( &m_DummyTail ); INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinkedList Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template CLinkedListType::~CLinkedList( void ) { ASSERT( IsEmpty() ); // Delete all objects on the linked-list Clear(); DeleteFreePool(); DELETE_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: Default CLinkedList::CIterator Constructor Description: Creates a NULL CIterator. Input: none Output: none \*****************************************************************************/ template CLinkedListType::CIterator::CIterator( void ) { m_Ptr = NULL; } /*****************************************************************************\ Function: CLinkedList::CIterator Constructor Description: Constructs a CIterator to the specified linked list node pointer. Input: CNode* - pointer to create an iterator to. Output: none \*****************************************************************************/ template CLinkedListType::CIterator::CIterator( CNode* ptr ) { ASSERT( ptr ); m_Ptr = ptr; } /*****************************************************************************\ Function: CLinkedList::CIterator Copying Constructor Description: Constructs a CIterator being copy of other iterator. Input: const CIterator & - reference to iterator to copy from. Output: none \*****************************************************************************/ template CLinkedListType::CIterator::CIterator( const CIterator &iterator ) { m_Ptr = iterator.m_Ptr; } /*****************************************************************************\ Function: CLinkedList::CIterator::operator-- Description: Iterates backwards through the linked list via predecrement. Input: none Output: CLinkedList CIterator& - iterator to the previous node in the list. \*****************************************************************************/ template typename CLinkedListType::CIterator& CLinkedListType::CIterator::operator--( void ) { m_Ptr = m_Ptr->GetPrevious(); ASSERT( m_Ptr ); return *this; } /*****************************************************************************\ Function: CLinkedList::CIterator::operator++ Description: Iterates forwards through the linked list via preincrement. Input: none Output: CLinkedList CIterator& - iterator to the next node in the list. \*****************************************************************************/ template typename CLinkedListType::CIterator& CLinkedListType::CIterator::operator++( void ) { m_Ptr = m_Ptr->GetNext(); ASSERT( m_Ptr ); return *this; } /*****************************************************************************\ Function: CLinkedList::CIterator::operator== Description: Input: const CIterator& - pointer to the iterator to compare to. Output: bool - true if this iterator and the passed-in iterator point to the same linked list node. \*****************************************************************************/ template bool CLinkedListType::CIterator::operator==( const CIterator& iterator ) const { return m_Ptr == iterator.m_Ptr; } /*****************************************************************************\ Function: CLinkedList::CIterator::operator!= Description: Input: const CIterator& - pointer to the iterator to compare to. Output: bool - true if this iterator and the passed-in iterator point to different linked list nodes. \*****************************************************************************/ template bool CLinkedListType::CIterator::operator!=( const CIterator& iterator ) const { return m_Ptr != iterator.m_Ptr; } /*****************************************************************************\ Function: CLinkedList::CIterator::operator= Description: Input: const CIterator& - reference to the iterator to copy from. Output: const CIterator & - reference to self \*****************************************************************************/ template typename CLinkedListType::CIterator &CLinkedListType::CIterator::operator=( const CIterator &iterator ) { m_Ptr = iterator.m_Ptr; return *this; } /*****************************************************************************\ Function: CLinkedList::CIterator::operator* Description: Returns a reference to the item that this iterator points to. Input: none Output: Type& - reference to the item that this iterator points to. \*****************************************************************************/ template Type& CLinkedListType::CIterator::operator*( void ) { return m_Ptr->GetElement(); } /*****************************************************************************\ Function: CLinkedList::CIterator::IsNull Description: Determines if the iterator has been assigned Input: none Output: bool \*****************************************************************************/ template bool CLinkedListType::CIterator::IsNull( void ) const { return ( m_Ptr == NULL ); } /*****************************************************************************\ Function: CLinkedList::CIterator::SetNull Description: Sets the iterator pointer to null Input: none Output: none \*****************************************************************************/ template void CLinkedListType::CIterator::SetNull( void ) { m_Ptr = NULL; } /*****************************************************************************\ Function: Default CLinkedList::CConstIterator Constructor Description: Creates a NULL CConstIterator. Input: none Output: none \*****************************************************************************/ template CLinkedListType::CConstIterator::CConstIterator( void ) { m_Ptr = NULL; } /*****************************************************************************\ Function: CLinkedList::CConstIterator Constructor Description: Constructs a CConstIterator to the specified const linked list node pointer. Input: const CNode* - pointer to create an iterator to. Output: none \*****************************************************************************/ template CLinkedListType::CConstIterator::CConstIterator( const CNode* ptr ) { ASSERT( ptr ); m_Ptr = ptr; } /*****************************************************************************\ Function: CLinkedList::CConstIterator Constructor Description: Constructs a CConstIterator from a CIterator. Input: const CIterator& - CIterator to convert to a CConstIterator. Output: none \*****************************************************************************/ template CLinkedListType::CConstIterator::CConstIterator( const CIterator& iterator ) { ASSERT( iterator.m_Ptr ); m_Ptr = iterator.m_Ptr; } /*****************************************************************************\ Function: CLinkedList::CConstIterator::operator-- Description: Iterates backwards through the linked list via predecrement. Input: none Output: CLinkedList CConstIterator& - iterator to the previous node in the list. \*****************************************************************************/ template typename CLinkedListType::CConstIterator& CLinkedListType::CConstIterator::operator--( void ) { m_Ptr = m_Ptr->GetPrevious(); ASSERT( m_Ptr ); return *this; } /*****************************************************************************\ Function: CLinkedList::CConstIterator::operator++ Description: Iterates forwards through the linked list via preincrement. Input: none Output: CLinkedList CConstIterator& - iterator to the next node in the list. \*****************************************************************************/ template typename CLinkedListType::CConstIterator& CLinkedListType::CConstIterator::operator++( void ) { m_Ptr = m_Ptr->GetNext(); ASSERT( m_Ptr ); return *this; } /*****************************************************************************\ Function: CLinkedList::CConstIterator::operator== Description: Input: const CConstIterator& - pointer to the iterator to compare to. Output: bool - true if this iterator and the passed-in iterator point to the same linked list node. \*****************************************************************************/ template bool CLinkedListType::CConstIterator::operator==( const CConstIterator& iterator ) const { return m_Ptr == iterator.m_Ptr; } /*****************************************************************************\ Function: CLinkedList::CConstIterator::operator!= Description: Input: const CConstIterator& - pointer to the iterator to compare to. Output: bool - true if this iterator and the passed-in iterator point to different linked list nodes. \*****************************************************************************/ template bool CLinkedListType::CConstIterator::operator!=( const CConstIterator& o ) const { return m_Ptr != o.m_Ptr; } /*****************************************************************************\ Function: CLinkedList::CConstIterator::operator* Description: Returns a const reference to the item that this iterator points to. Input: none Output: const Type& - reference to the item that this iterator points to. \*****************************************************************************/ template const Type& CLinkedListType::CConstIterator::operator*( void ) { return m_Ptr->GetElement(); } /*****************************************************************************\ Function: CLinkedList::CConstIterator::IsNull Description: Determines if the iterator has been assigned Input: none Output: bool \*****************************************************************************/ template bool CLinkedListType::CConstIterator::IsNull( void ) const { return ( m_Ptr == NULL ); } /*****************************************************************************\ Function: CLinkedList::CConstIterator::SetNull Description: Sets the iterator pointer to null Input: none Output: none \*****************************************************************************/ template void CLinkedListType::CConstIterator::SetNull( void ) { m_Ptr = NULL; } /*****************************************************************************\ Function: CLinkedList::IsEmpty Description: Returns if the linked-list is empty Input: none Output: bool - true or false \*****************************************************************************/ template bool CLinkedListType::IsEmpty( void ) const { return ( m_DummyTail.GetNext() == &m_DummyTail ); } /*****************************************************************************\ Function: CLinkedList::GetCount Description: Returns the number of elements in the linked-list Input: none Output: DWORD - number of elements \*****************************************************************************/ template DWORD CLinkedListType::GetCount( void ) const { return m_Count; } /*****************************************************************************\ Function: CLinkedList::operator= Description: Copies a linked-list to this linked-list Input: CLinkedListType &llist - linked-list to copy Output: CLinkedListType& - *this \*****************************************************************************/ template CLinkedListType& CLinkedListType::operator= ( const CLinkedListType &llist ) { // Copy from back-to-front so we wind up with the same order of elements const CNode* pDummyTail = &llist.m_DummyTail; const CNode* pNode = pDummyTail->GetPrevious(); while( pNode != pDummyTail ) { Add( pNode->GetElement() ); pNode = pNode->GetPrevious(); } return *this; } /*****************************************************************************\ Function: CLinkedList::Begin Description: Returns an iterator to the first node in the linked list. Input: none Output: CLinkedListType::CIterator \*****************************************************************************/ template typename CLinkedListType::CIterator CLinkedListType::Begin( void ) { return CIterator( m_DummyTail.GetNext() ); } /*****************************************************************************\ Function: CLinkedList::Get Description: Returns an iterator to the nth node in the linked list. Input: const DWORD index - index of node requesting Output: CLinkedListType::CIterator \*****************************************************************************/ template typename CLinkedListType::CIterator CLinkedListType::Get( const DWORD index ) { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); CIterator iterator; if( index <= ( m_Count - 1 ) ) { if( index <= ( m_Count / 2 ) ) { iterator = Begin(); for( DWORD i = 0; i < index; i++ ) { ++iterator; } } else { iterator = End(); for( DWORD i = m_Count; i > index; i-- ) { --iterator; } } } else { iterator = End(); } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return iterator; } /*****************************************************************************\ Function: CLinkedList::End Description: Returns an iterator to the last (dummy) node in the linked list. Input: none Output: CLinkedListType::CIterator \*****************************************************************************/ template typename CLinkedListType::CIterator CLinkedListType::End( void ) { return CIterator( &m_DummyTail ); } /*****************************************************************************\ Function: CLinkedList::Begin Description: Returns a const iterator to the first node in the linked list. Input: none Output: CLinkedListType::CConstIterator \*****************************************************************************/ template typename CLinkedListType::CConstIterator CLinkedListType::Begin( void ) const { return CConstIterator( m_DummyTail.GetNext() ); } /*****************************************************************************\ Function: CLinkedList::Get Description: Returns a const iterator to the nth node in the linked list. Input: const DWORD index - index of node requesting Output: CLinkedListType::CConstIterator \*****************************************************************************/ template typename CLinkedListType::CConstIterator CLinkedListType::Get( const DWORD index ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); CConstIterator iterator; if( index <= ( m_Count - 1 ) ) { if( index <= ( m_Count / 2 ) ) { iterator = Begin(); for( DWORD i = 0; i < index; i++ ) { ++iterator; } } else { iterator = End(); for( DWORD i = m_Count; i > index; i-- ) { --iterator; } } } else { iterator = End(); } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return iterator; } /*****************************************************************************\ Function: CLinkedList::End Description: Returns a const iterator to the last (dummy) node in the linked list. Input: none Output: CLinkedListType::CConstIterator \*****************************************************************************/ template typename CLinkedListType::CConstIterator CLinkedListType::End( void ) const { return CConstIterator( &m_DummyTail ); } /*****************************************************************************\ Function: CLinkedList::Find Description: Finds the first instance of the specified element in the linked-list Input: Type element - element to find Output: CIterator - iterator to the node containing the element \*****************************************************************************/ template typename CLinkedListType::CIterator CLinkedListType::Find( const Type &element ) { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); CNode* pDummyTail = &m_DummyTail; CNode* pNode = m_DummyTail.GetNext(); while( pNode != pDummyTail ) { // If this node contains the element, then // return an iterator to this node if( pNode->GetElement() == element ) { RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return CIterator( pNode ); } // Get the next node pNode = pNode->GetNext(); } // Node not found RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return End(); } /*****************************************************************************\ Function: CLinkedList::Find Description: Finds the first instance of the specified element in the linked-list Input: Type element - element to find Output: CConstIterator - iterator to the node containing the element \*****************************************************************************/ template typename CLinkedListType::CConstIterator CLinkedListType::Find( const Type &element ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); const CNode* pDummyTail = &m_DummyTail; const CNode* pNode = m_DummyTail.GetNext(); while( pNode != pDummyTail ) { // If this node contains the element, then // return an iterator to this node if( pNode->GetElement() == element ) { RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return CConstIterator( pNode ); } // Get the next node pNode = pNode->GetNext(); } // Node not found RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return End(); } /*****************************************************************************\ Function: CLinkedList::Add Description: Adds the specified element to the beginning of the linked-list Input: const Type& element - element to add to the linked-list Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CLinkedListType::Add( const Type &element ) { const bool success = Add( Begin(), element ); return success; } /*****************************************************************************\ Function: CLinkedList::Remove Description: Removes the first instance of the specified element from the linked-list Input: Type element - element to remove Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CLinkedListType::Remove( const Type &element ) { // Find the specified element in the list CIterator iterator = Find( element ); const bool success = Remove( iterator ); return success; } /*****************************************************************************\ Function: CLinkedList::Add Description: Adds the specified element to the linked-list at the location specified by the passed-in iterator. The item is added before the passed-in iterator. Input: const CIterator& location - place in the list to add the element const Type& element - element to add to the linked-list Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CLinkedListType::Add( const CIterator &location, const Type &element ) { // If necessary, make sure we do not add an element twice ASSERT( ( AreLinkedListDuplicatesSupported::value == true ) || ( Find( element ) == End() ) ); ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); bool success = false; // Create a new object for the element CNode* pNode = CreateNode( element ); if( pNode ) { pNode->Insert( location.m_Ptr ); m_Count++; // Element successfully added success = true; } else { ASSERT( 0 ); // Element not added success = false; } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CLinkedList::Remove Description: Removes the node specified by the passed-in iterator. Input: const CIterator& - location to remove Output: bool - SUCCESS or FAIL \*****************************************************************************/ template bool CLinkedListType::Remove( const CIterator &location ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); bool success = false; if( location == End() ) { // Element not removed success = false; } else { CNode* pNode = location.m_Ptr; success = Remove( pNode ); } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CLinkedList::Clear Description: clears the list Input: none Output: none \*****************************************************************************/ template void CLinkedListType::Clear( void ) { // Delete all objects on the linked-list while( !IsEmpty() ) { Remove( Begin() ); } } /*****************************************************************************\ Function: CLinkedList::Splice Description: Splices some or all of a source list into this list. Upon return the source list will be smaller than it was before (assuming the source iterator is not the list end). This would be a constant time operation, but we need to maintain the list of counts in each list. As such, it is a linear time operation, albeit a fast linear operation. Input: const CIterator& dstLocation - location to put the source list's nodes; the source lists's nodes will be spliced before this node const CIterator& srcLocation - the first node in the source list that will be spliced into this list CLinkedListType& srcList - source list to splice into this list Output: none \*****************************************************************************/ template void CLinkedListType::Splice( const CIterator &dstLocation, const CIterator &srcLocation, CLinkedListType &srcList ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); if( this != &srcList ) { if( !srcList.IsEmpty() ) { // Figure out how many nodes we're going to splice. CIterator countIterator = srcLocation; DWORD count = 0; while( countIterator != srcList.End() ) { count++; ++countIterator; } // Update the counts. m_Count += count; srcList.m_Count -= count; // Actually do the splicing. CNode* pDstNode = dstLocation.m_Ptr; CNode* pSrcStartNode = srcLocation.m_Ptr; CNode* pSrcEndNode = srcList.m_DummyTail.GetPrevious(); pSrcStartNode->GetPrevious()->SetNext( &srcList.m_DummyTail ); srcList.m_DummyTail.SetPrevious( pSrcStartNode->GetPrevious() ); pDstNode->GetPrevious()->SetNext( pSrcStartNode ); pSrcStartNode->SetPrevious( pDstNode->GetPrevious() ); pSrcEndNode->SetNext( pDstNode ); pDstNode->SetPrevious( pSrcEndNode ); } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinkedList::SpliceListPartAtTheEnd Description: Splices some or all (interval) of a source list at the end of this list. Upon return the source list will be smaller than it was before (assuming the source iterator is not the list end). This would be a constant time operation, but we need to maintain the list of counts in each list. As such, it is a linear time operation, albeit a fast linear operation. Input: CLinkedListType& srcList - source list to splice into this list. const CIterator &srcStartLocation - the first node in the source list that will be spliced into this list. const CIterator &srcEndLocation - the first node AFTER the last in the source list that will be spliced into this list (this element will not be moved). Output: none \*****************************************************************************/ template void CLinkedListType::SpliceListPartAtTheEnd( CLinkedListType &srcList, const CIterator &srcStartLocation, const CIterator &srcEndLocation ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); if( this != &srcList ) { if( !srcList.IsEmpty() && ( srcStartLocation.m_Ptr != srcEndLocation.m_Ptr ) ) { // Figure out how many nodes we're going to splice. CIterator countIterator = srcStartLocation; DWORD count = 0; while( countIterator != srcEndLocation ) { count++; ++countIterator; } // Update the counts. m_Count += count; srcList.m_Count -= count; // Actually do the splicing. // last before End. CNode* pDstNode = m_DummyTail.GetPrevious(); CNode* pSrcStartNode = srcStartLocation.m_Ptr; CNode* pSrcEndNode = srcEndLocation.m_Ptr->GetPrevious(); // Seal the gap after removed part pSrcStartNode->GetPrevious()->SetNext( srcEndLocation.m_Ptr ); srcEndLocation.m_Ptr->SetPrevious( pSrcStartNode->GetPrevious() ); // splice in. pDstNode->SetNext( pSrcStartNode ); pSrcStartNode->SetPrevious( pDstNode ); pSrcEndNode->SetNext( &m_DummyTail ); m_DummyTail.SetPrevious( pSrcEndNode ); } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinkedList::Set Description: Sets the contents of the node pointed to by location with element provided Input: const CIterator &location - location to set the element const Type &element - the element to set Output: bool \*****************************************************************************/ template void CLinkedListType::Set( const CIterator &location, const Type &element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); if( location.m_Ptr ) { location.m_Ptr->SetElement( element ); } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinkedList::DeleteFreePool Description: Deletes all memory on the free pool Input: none Output: none \*****************************************************************************/ template void CLinkedListType::DeleteFreePool( void ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); // Delete all objects on the free pool list while( m_FreePoolDummyTail.GetNext() != &m_FreePoolDummyTail ) { CNode* pNode = m_FreePoolDummyTail.GetNext(); pNode->Remove(); SafeDelete( pNode ); } m_FreePoolCount = 0; RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CLinkedList::DebugPrint Description: Prints the linked-list to std output for debug only Input: none Output: none \*****************************************************************************/ template void CLinkedListType::DebugPrint( void ) const { #ifdef _DEBUG DPF( GFXDBG_STDLIB, "%s\n", __FUNCTION__ ); DPF( GFXDBG_STDLIB, "\tAddress = %p\n", this ); DPF( GFXDBG_STDLIB, "\tType = %s\n", TYPEID_NAME(Type) ); const CNode* pDummyTail = &m_DummyTail; CNode* pNode = m_DummyTail.GetNext(); while( pNode != pDummyTail ) { DWORD index = 0; DPF( GFXDBG_STDLIB, "\t\tLinkedListNode[%u] = 0x%08x\n", index, *(DWORD*)&pNode->GetElement() ); index++; // Get the next node pNode = pNode->GetNext(); } #endif } /*****************************************************************************\ Function: CLinkedList::Remove Description: Removes the specified node from the linked-list Input: CNode* pNode - object to remove Output: none \*****************************************************************************/ template bool CLinkedListType::Remove( CNode* &pNode ) { bool success = false; if( pNode ) { // Remove the node from the linked-list pNode->Remove(); // Delete the node DeleteNode( pNode ); m_Count--; success = true; } return success; } /*****************************************************************************\ Function: CLinkedList::CreateNode Description: Creates a node Input: const Type &element Output: CNode* \*****************************************************************************/ template typename CLinkedListType::CNode* CLinkedListType::CreateNode( const Type &element ) { CNode* pNode = NULL; if( m_FreePoolDummyTail.GetNext() != &m_FreePoolDummyTail ) { pNode = m_FreePoolDummyTail.GetNext(); pNode->Remove(); --m_FreePoolCount; pNode->SetElement( element ); } else { pNode = new CNode( element ); } return pNode; } /*****************************************************************************\ Function: CLinkedList::DeleteNode Description: Deletes a node Input: CNode* pNode Output: none \*****************************************************************************/ template void CLinkedListType::DeleteNode( CNode* &pNode ) { const DWORD cMaxFreePoolCount = 32; if( m_FreePoolCount <= cMaxFreePoolCount ) { pNode->Insert( m_FreePoolDummyTail.GetNext() ); ++m_FreePoolCount; } else { SafeDelete( pNode ); } } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/LruHashTable.h000066400000000000000000000440221363533017100250560ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "HashTable.h" #include "LRUSet.h" namespace iSTD { namespace HashingFunctions { enum HashingFunctionEnum { eAbrash = 0, HashingFunctionCount, }; }; #define LruHashTableTemplateList class KeyType, class ValueType, class CAllocatorType #define LruHashTableType CLruHashTable /*****************************************************************************\ Class: CLruHashTable Description: Maintains a hash table and employs LRUSet objects at each hash index to evict older items. \*****************************************************************************/ template class CLruHashTable : public CObject { public: class CLruHashTableIterator { friend class CLruHashTable; public: bool Next(ValueType& out_value); private: CLruHashTableIterator() {} CLruHashTable* hashTablePtr; int currentHashIndex; typename LRUClassType::CLRUSetIterator* currentSetIterator; }; friend class CLruHashTableIterator; CLruHashTable(int in_hashTableSize, int in_lruSetSize, HashingFunctions::HashingFunctionEnum in_hashingFunction = HashingFunctions::eAbrash); ~CLruHashTable(); bool IsItemInHash(const KeyType& in_key); bool IsItemInHash(const KeyType& in_key, ValueType& out_value); bool TouchItem(const KeyType& in_key, const ValueType& in_value); bool TouchItem(const KeyType& touch_key, const ValueType& touch_value, KeyType& evict_key, ValueType& evict_value); void DebugPrint(const char* in_filename); CLruHashTableIterator* InitAndReturnIterator(); protected: int m_hashTableSize, m_lruSetSize; DWORD MakeHashValue(const KeyType& in_key); int GoodTableSizes(int in_requestedSize); LRUClassType* m_hashArray; typename LRUClassType::SLRUSetItem* m_linkedListElements; HashingFunctions::HashingFunctionEnum m_hashingFunction; CLruHashTableIterator m_iterator; }; /*****************************************************************************\ Function: CLruHashTable() Description: Input: none Output: none \*****************************************************************************/ template LruHashTableType::CLruHashTable( int in_hashTableSize, int in_lruSetSize, HashingFunctions::HashingFunctionEnum in_hashingFunction) : m_hashingFunction(in_hashingFunction) { ASSERT(in_hashTableSize > 0); ASSERT(in_lruSetSize > 0); m_hashTableSize = GoodTableSizes(in_hashTableSize); m_lruSetSize = in_lruSetSize; int strideSize = sizeof(LRUClassType::SLRUSetItem) * m_lruSetSize; m_hashArray = new LRUClassType[m_hashTableSize]; while(m_hashArray == NULL) { //allocation failed, try reducing the size int newSize = GoodTableSizes(m_hashTableSize - 1); if(newSize == m_hashTableSize) //reached the minimum size, time to fail out { //at this point there is no hope ASSERT(m_hashArray != NULL); return; } m_hashArray = new LRUClassType[m_hashTableSize]; } m_linkedListElements = new typename LRUClassType::SLRUSetItem[m_lruSetSize * m_hashTableSize]; while(m_linkedListElements == NULL) { //allocation failed, try reducing the size int newSize = in_lruSetSize / 2; if(newSize == in_lruSetSize) //reached the minimum size of 1, time to fail out { //at this point there is no hope ASSERT(m_linkedListElements != NULL); return; } m_linkedListElements = new typename LRUClassType::SLRUSetItem[m_lruSetSize * m_hashTableSize]; } BYTE* linkedListElementsPtr = (BYTE*)m_linkedListElements; for(int index = 0; index < m_hashTableSize; index++) { new (&m_hashArray[index]) LRUClassType(m_lruSetSize, (typename LRUClassType::SLRUSetItem*)linkedListElementsPtr); linkedListElementsPtr += strideSize; } } /*****************************************************************************\ Function: ~CLruHashTable() Description: Input: none Output: none \*****************************************************************************/ template LruHashTableType::~CLruHashTable() { delete[] m_hashArray; delete[] m_linkedListElements; } /*****************************************************************************\ Function: IsItemInHash() Description: Tests for the existance of an item in the table. This overloaded version is used only for testing existance, see the other overloaded version for retrieval of values. Input: KeyType in_key - The key value to search for. Output: bool - true or false for the existance of the key in the set. \*****************************************************************************/ template bool LruHashTableType::IsItemInHash(const KeyType& in_key) { DWORD hashIndex = MakeHashValue(in_key); hashIndex %= m_hashTableSize; return m_hashArray[hashIndex].IsItemInSet(in_key); } /*****************************************************************************\ Function: IsItemInHash() Description: Tests for the existance of an item in the table. This overloaded version is used for retrieval of values. See the other overloaded version for simple tests of existance in the table. If the return value is false (key not found) then the out_value is unchanged. Input: KeyType in_key - The key value to search for. ValueType& out_value - returns the value associated with the key, if the key was found. If the key was not found then this value is not set and the return is false. Output: bool - true or false for the existance of the key in the set. \*****************************************************************************/ template bool LruHashTableType::IsItemInHash( const KeyType& in_key, ValueType& out_value) { DWORD hashIndex = MakeHashValue(in_key); hashIndex %= m_hashTableSize; return m_hashArray[hashIndex].IsItemInSet(in_key, out_value); } /*****************************************************************************\ Function: TouchItem() Description: Attempts to find the key specified. If found the values are compared, if the values match then the item is moved to the most-recently-used position of that hash index. If not found the item is added to the LRUSet, possibly evicting an item if the set is full. Input: KeyTypetouch_key - The key value to search for. ValueType touch_value - the associated value stored with the key. Output: bool - true if the item was evicted from the set. \*****************************************************************************/ template bool LruHashTableType::TouchItem( const KeyType& touch_key, const ValueType& touch_value) { DWORD hashIndex = MakeHashValue(touch_key); hashIndex %= m_hashTableSize; return m_hashArray[hashIndex].TouchItem(touch_key, touch_value); } /*****************************************************************************\ Function: TouchItem() Description: Attempts to find the key specified. If found the values are compared, if the values match then the item is moved to the most-recently-used position of that hash index. If not found the item is added to the LRUSet, possibly evicting an item if the set is full. Input: KeyType touch_key - The key value to search for. ValueType touch_value - the associated value stored with the key. KeyType evict_key - if return is false, then this value is that of the key which was evicted to add the touch_key to the set. ValueType evict_value - if return is false, then this value is that of the value which was evicted to add the touch_value to the set. Output: bool - true if the item was evicted from the set. \*****************************************************************************/ template bool LruHashTableType::TouchItem( const KeyType& touch_key, const ValueType& touch_value, KeyType& evict_key, ValueType& evict_value) { DWORD hashIndex = MakeHashValue(touch_key); hashIndex %= m_hashTableSize; return m_hashArray[hashIndex].TouchItem(touch_key, touch_value, evict_key, evict_value); } /*****************************************************************************\ Function: MakeHashValue() Description: Protected function. Converts a KeyType into a hash value with the remainder of the modulo used as the hash index. Input: KeyType in_key - the key value to convert. Output: DWORD - hash value for the key. \*****************************************************************************/ template DWORD LruHashTableType::MakeHashValue(const KeyType& in_key) { const __m128i* keyPointer = (__m128i*)&in_key; DWORD hashCode = 0; #if defined(_WIN32) && defined(_MSC_VER) ASSERT( HashingFunctions::HashingFunctionCount == 1 ); switch(m_hashingFunction) { case HashingFunctions::eAbrash: { int fullSections = sizeof(KeyType) / sizeof(__m128i); __m128i runningSimdHashCode = _mm_setzero_si128(); __m128i shiftConstant = _mm_set_epi32(0,0,0,7); //iterate over 128-bit blocks generating a hash code for(int simdBlock = 0; simdBlock < fullSections; simdBlock++) { //add the magic number from Abrash's code to the running hash code runningSimdHashCode = _mm_add_epi32(runningSimdHashCode, _mm_set1_epi32(0x83765503)); //shift left by 7 and add to self runningSimdHashCode = _mm_add_epi32(runningSimdHashCode, _mm_sll_epi32(runningSimdHashCode, shiftConstant)); //load 128 bits of the key, xor into running value. keyPointer is typed DWORD* thus the times 4 __m128i readin = _mm_loadu_si128((__m128i const*)keyPointer); runningSimdHashCode = _mm_xor_si128(runningSimdHashCode, _mm_loadu_si128(keyPointer)); //keyPointer is typed DWORD*, +4 moves ahead 128-bits keyPointer++; } //if the value did not evenly divide into 128-bit blocks if(sizeof(KeyType) % sizeof(__m128i) != 0) { //add the magic number from Abrash's code to the running hash code runningSimdHashCode = _mm_add_epi32(runningSimdHashCode, _mm_set1_epi32(0x83765503)); //shift left by 7 and add to self runningSimdHashCode = _mm_add_epi32(runningSimdHashCode, _mm_sll_epi32(runningSimdHashCode, shiftConstant)); //load 128 bits of the key, xor into running value. keyPointer is typed DWORD* thus the times 4 __m128i partialKey = _mm_loadu_si128(keyPointer); //shift out the values which extend past the length of the key partialKey = _mm_slli_si128(partialKey, (16 - (sizeof(KeyType) % sizeof(__m128i)))); runningSimdHashCode = _mm_xor_si128(partialKey, runningSimdHashCode); } //shuffle and xor field 0 and 1, then 2 and 3 __m128i shuffledHashCode = _mm_shuffle_epi32(runningSimdHashCode, _MM_SHUFFLE(2,3,0,1)); runningSimdHashCode = _mm_xor_si128(runningSimdHashCode, shuffledHashCode); //shuffle and xor 0 and 2, 1 and 3 have already been worked in. shuffledHashCode = _mm_shuffle_epi32(runningSimdHashCode, _MM_SHUFFLE(1,0,3,2)); runningSimdHashCode = _mm_xor_si128(runningSimdHashCode, shuffledHashCode); //write out least significant 32-bits to hashCode. hashCode = _mm_cvtsi128_si32(runningSimdHashCode); break; }// case HashingFunctions::eAbrash: default: ASSERT(0); //not good } return hashCode; #else // _MSC_VER ASSERT( IsAligned( &in_key, sizeof(DWORD) ) ); ASSERT( IsAligned( &hashCode, sizeof(DWORD) ) ); const DWORD* pKeyValue = (const DWORD*)&in_key; hashCode = *pKeyValue++; const DWORD count = (DWORD)( sizeof(KeyType) / sizeof(DWORD) ); for( DWORD i = 1; i < count; ++i ) { const DWORD data = *pKeyValue++; hashCode = ( hashCode << 1 ) ^ data; } return hashCode; #endif // _MSC_VER } /*****************************************************************************\ Function: DebugPrint() Description: Outputs to a file the hash table occupancy, the number of elements stored at each hash index. The value at each index cannot be greater than the LRUSet size. Input: const char* in_filename - file to write to. Output: none \*****************************************************************************/ template void LruHashTableType::DebugPrint(const char* in_filename) { FILE* fileHandle = fopen(in_filename, "w"); for(unsigned int index = 0; index < m_hashTableSize; index++) { fprintf(fileHandle, "%u,", index); fprintf(fileHandle, "%d\n", m_hashArray[index].GetOccupancy()); } fclose(fileHandle); } /*****************************************************************************\ Function: GoodTableSizes() Description: Revises the hash table size to a better size for the hardware. Input: int in_requestedSize - size requested by the user Output: int - size suggested. \*****************************************************************************/ template int LruHashTableType::GoodTableSizes(int in_requestedSize) { if( in_requestedSize >= 6151 ) { return 6151; } else if( in_requestedSize >= 3079 ) { return 3079; } else if( in_requestedSize >= 1543 ) { return 1543; } else if( in_requestedSize >= 769 ) { return 769; } else if( in_requestedSize >= 389 ) { return 389; } else if( in_requestedSize >= 193 ) { return 193; } else if( in_requestedSize >= 97 ) { return 97; } else { return 53; } } /*****************************************************************************\ Function: Next() Description: Returns the current element of the iterator and moves it to the next item. Usage suggestion is as follows (short hand c++): iterator = InitAndReturnIterator(); ValueType value; while(iterator.Next(value)) { //do something with value } Input: Output: return bool - true if there is a value to give, if so out_value is set, otherwise there are no more elements and out_value was not modified. ValueType out_value - is set to the value of the current element for the iterator \*****************************************************************************/ template bool LruHashTableType::CLruHashTableIterator::Next(ValueType& out_value) { if(currentHashIndex == hashTablePtr->m_hashTableSize) { //at the end, no other elements to give. user must use //InitAndReturnIterator() again. return false; } if(currentSetIterator->HasNext()) { //the current set still has more elements, return the next one out_value = currentSetIterator->Next(); return true; } for(currentHashIndex++; currentHashIndex < hashTablePtr->m_hashTableSize; currentHashIndex++) { currentSetIterator = hashTablePtr->m_hashArray[currentHashIndex].InitAndReturnIterator(); if(currentSetIterator->HasNext()) { out_value = currentSetIterator->Next(); return true; } } //reached the end after searching, no new elements. return false; } /*****************************************************************************\ Function: GoodTableSizes() Description: Revises the hash table size to a better size for the hardware. Input: int in_requestedSize - size requested by the user Output: int - size suggested. \*****************************************************************************/ template typename LruHashTableType::CLruHashTableIterator* LruHashTableType::InitAndReturnIterator() { //search until the first set iterator is found, if the end is reached then //the whole hash table is empty. for(m_iterator.currentHashIndex = 0; m_iterator.currentHashIndex < m_hashTableSize; m_iterator.currentHashIndex++) { m_iterator.currentSetIterator = m_hashArray[m_iterator.currentHashIndex].InitAndReturnIterator(); if(m_iterator.currentSetIterator->HasNext()) { break; } } m_iterator.hashTablePtr = this; return &m_iterator; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Macros.h000066400000000000000000000032721363533017100237660ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once /*****************************************************************************\ MACRO: ISTD_DISALLOW_COPY_AND_ASSIGN Description: A macro to disallow the copy constructor and operator= functions This should be used in the private: declarations for a class \*****************************************************************************/ #define ISTD_DISALLOW_COPY_AND_ASSIGN( TypeName ) \ TypeName(const TypeName&); \ TypeName& operator=(const TypeName&) intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/MemCopy.h000066400000000000000000003722571363533017100241270ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "types.h" #include "Debug.h" #include "utility.h" #include #include "CpuUtil.h" #if !defined ( _MSC_VER ) #include "inc/common/secure_mem.h" #endif #if defined(_WIN32) #include #if defined ( _WIN64 ) && defined ( _In_ ) // NOTE: is not necessary here. // This is only an ugly workaround for a VS2008 bug that causes the compilation // issue on 64-bit DEBUG configuration. // Including "math.h" before "intrin.h" helps to get rid of the following warning: // warning C4985: 'ceil': attributes not present on previous declaration. #include #endif #include #define USE_SSE4_1 #else #include #endif typedef __m128 DQWORD; // 128-bits, 16-bytes typedef DWORD PREFETCH[8]; // 32-bytes typedef DWORD CACHELINE[8]; // 32-bytes typedef WORD DHWORD[32]; // 512-bits, 64-bytes namespace iSTD { enum { DWORD_SHIFT = 2, BYTE_TAIL = 3, INSTR_128_SHIFT = 4, CACHE_LINE_SHIFT = 6, DUAL_CACHE_SHIFT = 7, TAIL_SIZE = 15, INSTR_WIDTH_128 = 16, INSTR_WIDTH_256 = 32, CACHE_LINE_SIZE = 64, TIERED_TAIL = 127, DUAL_CACHE_SIZE = 128, MIN_ERMSB_ALIGNED = 4096, MIN_STREAM_SIZE = 524288, }; #ifdef _WIN64 # define USE_INLINE_ASM 0 #else # if defined _MSC_VER # define USE_INLINE_ASM 1 # else # define USE_INLINE_ASM 0 # endif #endif /*****************************************************************************\ Function Prototypes \*****************************************************************************/ inline void Prefetch( const void* ); inline void PrefetchBuffer( const void*, const size_t ); inline void CachelineFlush( const void* ); template inline void MemCopy( void*, const void* ); inline void MemCopy( void*, const void*, const size_t ); inline void MemCopyWC( void*, const void*, const size_t ); inline void MemCopySwapBytes( void*, const void*, const size_t, const unsigned int); inline void ScalarSwapBytes( __m128i**, const __m128i**, const size_t, const unsigned int); inline void SafeMemSet( void*, const int, const size_t ); inline int SafeMemCompare( const void*, const void*, const size_t ); inline void SafeMemMove( void*, const void*, const size_t ); #ifndef _WIN64 inline void __fastcall FastBlockCopyFromUSWC_SSE4_1_movntdqa_movdqa(void* dst, const void* src ); inline void __fastcall FastBlockCopyFromUSWC_SSE4_1_movntdqa_movdqu(void* dst, const void* src ); #endif inline void FastMemCopyFromWC( void* dst, const void* src, const size_t bytes, CPU_INSTRUCTION_LEVEL cpuInstructionLevel); inline void FastCpuBlt( BYTE*, const DWORD, BYTE*, const DWORD, const DWORD, DWORD ); inline void FindWordBufferMinMax( WORD*, const DWORD, WORD&, WORD& ); inline void FindDWordBufferMinMax( DWORD*, const DWORD, DWORD&, DWORD& ); inline void FindWordBufferMinMaxRestart( WORD*, const DWORD, const WORD, WORD&, WORD&, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ); inline void FindDWordBufferMinMaxRestart( DWORD*, const DWORD, const DWORD, DWORD&, DWORD&, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ); inline void FindWordBufferMinMaxCopy( WORD*, WORD*, const DWORD, WORD&, WORD& ); inline void FindDWordBufferMinMaxCopy( DWORD*, DWORD*, const DWORD, DWORD&, DWORD& ); inline void FindWordBufferMinMaxRestartCopy( WORD*, WORD*, const DWORD, const WORD, WORD&, WORD&, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ); inline void FindDWordBufferMinMaxRestartCopy( DWORD*, DWORD*, const DWORD, const DWORD, DWORD&, DWORD&, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ); /*****************************************************************************\ Inline Function: Prefetch Description: executes __asm prefetchnta \*****************************************************************************/ inline void Prefetch( const void* ptr ) { _mm_prefetch( (const char*)ptr, _MM_HINT_NTA ); } /*****************************************************************************\ Inline Function: PrefetchBuffer Description: executes __asm prefetchnta \*****************************************************************************/ inline void PrefetchBuffer( const void* pBuffer, const size_t bytes ) { const size_t cachelines = bytes / sizeof(PREFETCH); for( size_t i = 0; i <= cachelines; i++ ) { _mm_prefetch( (const char*)pBuffer + i * sizeof(PREFETCH), _MM_HINT_NTA ); } } /*****************************************************************************\ Inline Function: CachelineFlush Description: executes __asm clflush \*****************************************************************************/ inline void CachelineFlush( const void* ptr ) { _mm_clflush( (char*)ptr ); } /*****************************************************************************\ Inline Function: MemCopy Description: Templated Exception Handler Memory Copy function \*****************************************************************************/ template inline void MemCopy( void* dst, const void* src ) { MemCopy(dst, src, size); } template <> inline void MemCopy<1>( void* dst, const void* src ) { const BYTE* pSrc = reinterpret_cast(src); BYTE* pDst = reinterpret_cast(dst); *pDst = *pSrc; } template <> inline void MemCopy<2>( void* dst, const void* src ) { const WORD* pSrc = reinterpret_cast(src); WORD* pDst = reinterpret_cast(dst); *pDst = *pSrc; } template <> inline void MemCopy<4>( void* dst, const void* src ) { const UINT32* pSrc = reinterpret_cast(src); UINT32* pDst = reinterpret_cast(dst); *pDst = *pSrc; } template <> inline void MemCopy<8>( void* dst, const void* src ) { const UINT64* pSrc = reinterpret_cast(src); UINT64* pDst = reinterpret_cast(dst); *pDst = *pSrc; } template <> inline void MemCopy<16>( void* dst, const void* src ) { const __m128i* pMMSrc = reinterpret_cast(src); __m128i* pMMDst = reinterpret_cast<__m128i*>(dst); __m128i xmm0 = _mm_loadu_si128(pMMSrc); _mm_storeu_si128(pMMDst, xmm0); } template <> inline void MemCopy<28>( void* dst, const void* src ) { const __m128i* pMMSrc = reinterpret_cast( src ); __m128i* pMMDst = reinterpret_cast<__m128i*>( dst ); __m128i xmm0 = _mm_loadu_si128( pMMSrc ); _mm_storeu_si128( pMMDst, xmm0 ); pMMSrc += 1; pMMDst += 1; const UINT64* pSrc64 = reinterpret_cast( pMMSrc ); UINT64* pDst64 = reinterpret_cast( pMMDst ); *pDst64 = *pSrc64; pDst64 += 1; pSrc64 += 1; const UINT32* pSrc32 = reinterpret_cast( pSrc64 ); UINT32* pDst32 = reinterpret_cast( pDst64 ); *pDst32 = *pSrc32; } /*****************************************************************************\ Inline Function: MemCopy Description: Exception Handler Memory Copy function \*****************************************************************************/ inline void MemCopy( void* dst, const void* src, const size_t bytes ) { #if defined ( _MSC_VER ) UINT8* pDst8 = reinterpret_cast( dst ); const UINT8* pSrc8 = reinterpret_cast( src ); size_t bytesRemaining = bytes; // handle invalid cases if( bytesRemaining == 0 ) return; // handle sizes <= 4 bytes if( bytesRemaining <= 4 ) { if( bytesRemaining == 1 ) { // copy 1 bytes *pDst8 = *pSrc8; return; } if( bytesRemaining == 2 ) { // copy 2 bytes *reinterpret_cast( pDst8 ) = *reinterpret_cast( pSrc8 ); return; } if( bytesRemaining == 3 ) { // copy 3 bytes *reinterpret_cast( pDst8 ) = *reinterpret_cast( pSrc8 ); *( pDst8 + 2 ) = *( pSrc8 + 2 ); return; } *reinterpret_cast( pDst8 ) = *reinterpret_cast( pSrc8 ); return; } // align destination to 4 byte boundary if size is > 8 bytes if( bytesRemaining > 8 && reinterpret_cast( pDst8 ) & 0x3 ) { // check for shift by 1 if( reinterpret_cast( pDst8 ) & 0x1 ) { *pDst8 = *pSrc8; bytesRemaining -= 1; pDst8 += 1; pSrc8 += 1; } // check for shift by 2 if( reinterpret_cast( pDst8 ) & 0x2 ) { *reinterpret_cast( pDst8 ) = *reinterpret_cast( pSrc8 ); bytesRemaining -= 2; pDst8 += 2; pSrc8 += 2; } } // handle sizes <= 64 bytes as series of 4 byte moves if( bytesRemaining <= CACHE_LINE_SIZE ) { const size_t ptrAdvance = bytesRemaining & ~0x3; // TODO: Need to see if we can mimic the jump table pDst8 += ptrAdvance; pSrc8 += ptrAdvance; switch( bytesRemaining / 4 ) { case 16: *reinterpret_cast( pDst8 - 64 ) = *reinterpret_cast( pSrc8 - 64 ); case 15: *reinterpret_cast( pDst8 - 60 ) = *reinterpret_cast( pSrc8 - 60 ); case 14: *reinterpret_cast( pDst8 - 56 ) = *reinterpret_cast( pSrc8 - 56 ); case 13: *reinterpret_cast( pDst8 - 52 ) = *reinterpret_cast( pSrc8 - 52 ); case 12: *reinterpret_cast( pDst8 - 48 ) = *reinterpret_cast( pSrc8 - 48 ); case 11: *reinterpret_cast( pDst8 - 44 ) = *reinterpret_cast( pSrc8 - 44 ); case 10: *reinterpret_cast( pDst8 - 40 ) = *reinterpret_cast( pSrc8 - 40 ); case 9: *reinterpret_cast( pDst8 - 36 ) = *reinterpret_cast( pSrc8 - 36 ); case 8: *reinterpret_cast( pDst8 - 32 ) = *reinterpret_cast( pSrc8 - 32 ); case 7: *reinterpret_cast( pDst8 - 28 ) = *reinterpret_cast( pSrc8 - 28 ); case 6: *reinterpret_cast( pDst8 - 24 ) = *reinterpret_cast( pSrc8 - 24 ); case 5: *reinterpret_cast( pDst8 - 20 ) = *reinterpret_cast( pSrc8 - 20 ); case 4: *reinterpret_cast( pDst8 - 16 ) = *reinterpret_cast( pSrc8 - 16 ); case 3: *reinterpret_cast( pDst8 - 12 ) = *reinterpret_cast( pSrc8 - 12 ); case 2: *reinterpret_cast( pDst8 - 8 ) = *reinterpret_cast( pSrc8 - 8 ); case 1: *reinterpret_cast( pDst8 - 4 ) = *reinterpret_cast( pSrc8 - 4 ); } // tail may have up to 3 bytes off if( bytesRemaining & 0x1 ) { *pDst8 = *pSrc8; bytesRemaining -= 1; pDst8 += 1; pSrc8 += 1; } if( bytesRemaining & 0x2 ) { *reinterpret_cast( pDst8 ) = *reinterpret_cast( pSrc8 ); bytesRemaining -= 2; pDst8 += 2; pSrc8 += 2; } } // size is > 64 bytes use SSE2 else { __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; // xmm registers // align the destination to 16 bytes if necessary const size_t alignDst16 = reinterpret_cast( pDst8 ) & TAIL_SIZE; if( alignDst16 != 0 ) { const size_t alignSize = 0x10 - alignDst16; // already aligned to 4 bytes previously, so remainder must be a multiple of 4 pDst8 += alignSize; pSrc8 += alignSize; switch( alignSize / 4 ) { case 3: *reinterpret_cast( pDst8 - 12 ) = *reinterpret_cast( pSrc8 - 12 ); case 2: *reinterpret_cast( pDst8 - 8 ) = *reinterpret_cast( pSrc8 - 8 ); case 1: *reinterpret_cast( pDst8 - 4 ) = *reinterpret_cast( pSrc8 - 4 ); } bytesRemaining -= alignSize; } // if the size is greater than 1/2 largest cache if( bytesRemaining > MIN_STREAM_SIZE ) { while( bytesRemaining >= 128 ) { pDst8 += 128; pSrc8 += 128; bytesRemaining -= 128; xmm0 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 128 )); xmm1 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 112 )); xmm2 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 96 )); xmm3 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 80 )); xmm4 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 64 )); xmm5 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 48 )); xmm6 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 32 )); xmm7 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 16 )); _mm_stream_si128( reinterpret_cast<__m128i*>( pDst8 - 128 ), xmm0 ); _mm_stream_si128( reinterpret_cast<__m128i*>( pDst8 - 112 ), xmm1 ); _mm_stream_si128( reinterpret_cast<__m128i*>( pDst8 - 96 ), xmm2 ); _mm_stream_si128( reinterpret_cast<__m128i*>( pDst8 - 80 ), xmm3 ); _mm_stream_si128( reinterpret_cast<__m128i*>( pDst8 - 64 ), xmm4 ); _mm_stream_si128( reinterpret_cast<__m128i*>( pDst8 - 48 ), xmm5 ); _mm_stream_si128( reinterpret_cast<__m128i*>( pDst8 - 32 ), xmm6 ); _mm_stream_si128( reinterpret_cast<__m128i*>( pDst8 - 16 ), xmm7); } // copy up to 128 bytes const size_t ptrAdvance = bytesRemaining & ~0xF; pDst8 += ptrAdvance; pSrc8 += ptrAdvance; switch( bytesRemaining / 16 ) { case 7: xmm0 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 112 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 112 ), xmm0 ); case 6: xmm1 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 96 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 96 ), xmm1 ); case 5: xmm2 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 80 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 80 ), xmm2 ); case 4: xmm3 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 64 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 64 ), xmm3 ); case 3: xmm4 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 48 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 48 ), xmm4 ); case 2: xmm5 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 32 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 32 ), xmm5 ); case 1: xmm6 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 16 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 16 ), xmm6 ); } bytesRemaining -= ptrAdvance; } // size is less than 1/2 the largest cache, copy either fully aligned or partially aligned else { const size_t alignSrc16 = reinterpret_cast( pSrc8 ) & 0xF; // copy with source un-aligned if( alignSrc16 != 0 ) { while( bytesRemaining >= 128 ) { pDst8 += 128; pSrc8 += 128; bytesRemaining -= 128; xmm0 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 128 )); xmm1 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 112 )); xmm2 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 96 )); xmm3 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 80 )); xmm4 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 64 )); xmm5 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 48 )); xmm6 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 32 )); xmm7 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 16 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 128 ), xmm0 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 112 ), xmm1 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 96 ), xmm2 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 80 ), xmm3 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 64 ), xmm4 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 48 ), xmm5 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 32 ), xmm6 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 16 ), xmm7 ); } // copy up to 128 bytes const size_t ptrAdvance = bytesRemaining & ~0xF; pDst8 += ptrAdvance; pSrc8 += ptrAdvance; switch( bytesRemaining / 16 ) { case 7: xmm0 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 112 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 112 ), xmm0 ); case 6: xmm1 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 96 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 96 ), xmm1 ); case 5: xmm2 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 80 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 80 ), xmm2 ); case 4: xmm3 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 64 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 64 ), xmm3 ); case 3: xmm4 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 48 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 48 ), xmm4 ); case 2: xmm5 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 32 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 32 ), xmm5 ); case 1: xmm6 = _mm_loadu_si128( reinterpret_cast( pSrc8 - 16 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 16 ), xmm6 ); } bytesRemaining -= ptrAdvance; } // copy with source aligned else { while( bytesRemaining >= 128 ) { pDst8 += 128; pSrc8 += 128; bytesRemaining -= 128; xmm0 = _mm_load_si128( reinterpret_cast( pSrc8 - 128 )); xmm1 = _mm_load_si128( reinterpret_cast( pSrc8 - 112 )); xmm2 = _mm_load_si128( reinterpret_cast( pSrc8 - 96 )); xmm3 = _mm_load_si128( reinterpret_cast( pSrc8 - 80 )); xmm4 = _mm_load_si128( reinterpret_cast( pSrc8 - 64 )); xmm5 = _mm_load_si128( reinterpret_cast( pSrc8 - 48 )); xmm6 = _mm_load_si128( reinterpret_cast( pSrc8 - 32 )); xmm7 = _mm_load_si128( reinterpret_cast( pSrc8 - 16 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 128 ), xmm0 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 112 ), xmm1 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 96 ), xmm2 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 80 ), xmm3 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 64 ), xmm4 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 48 ), xmm5 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 32 ), xmm6 ); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 16 ), xmm7 ); } // copy up to 128 bytes const size_t ptrAdvance = bytesRemaining & ~0xF; pDst8 += ptrAdvance; pSrc8 += ptrAdvance; switch( bytesRemaining / 16 ) { case 7: xmm0 = _mm_load_si128( reinterpret_cast( pSrc8 - 112 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 112 ), xmm0 ); case 6: xmm1 = _mm_load_si128( reinterpret_cast( pSrc8 - 96 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 96 ), xmm1 ); case 5: xmm2 = _mm_load_si128( reinterpret_cast( pSrc8 - 80 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 80 ), xmm2 ); case 4: xmm3 = _mm_load_si128( reinterpret_cast( pSrc8 - 64 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 64 ), xmm3 ); case 3: xmm4 = _mm_load_si128( reinterpret_cast( pSrc8 - 48 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 48 ), xmm4 ); case 2: xmm5 = _mm_load_si128( reinterpret_cast( pSrc8 - 32 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 32 ), xmm5 ); case 1: xmm6 = _mm_load_si128( reinterpret_cast( pSrc8 - 16 )); _mm_store_si128( reinterpret_cast<__m128i*>( pDst8 - 16 ), xmm6 ); } bytesRemaining -= ptrAdvance; } } // copy the tail up to 15 bytes if( bytesRemaining ) { const size_t ptrAdvance = bytesRemaining & ~0x3; pDst8 += ptrAdvance; pSrc8 += ptrAdvance; // copy last up to 12 bytes switch( bytesRemaining / 4 ) { case 3: *reinterpret_cast( pDst8 - 12 ) = *reinterpret_cast( pSrc8 - 12 ); case 2: *reinterpret_cast( pDst8 - 8 ) = *reinterpret_cast( pSrc8 - 8 ); case 1: *reinterpret_cast( pDst8 - 4 ) = *reinterpret_cast( pSrc8 - 4 ); } // copy last up to 3 bytes if( bytesRemaining & 0x1 ) { *pDst8 = *pSrc8; bytesRemaining -= 1; pDst8 += 1; pSrc8 += 1; } if( bytesRemaining & 0x2 ) { *reinterpret_cast( pDst8 ) = *reinterpret_cast( pSrc8 ); bytesRemaining -= 2; pDst8 += 2; pSrc8 += 2; } } } #else // #if defined ( _MSC_VER ) // Linux projects do not support standard types or memcpy_s ::memcpy_s(dst, bytes, src, bytes); #endif } /*****************************************************************************\ Inline Function: MemCopyWC Description: Memory copy to a destination that is un-cacheable, i.e host to gpu. Input: dst - pointer to write-combined destination buffer src - pointer to source buffer bytes - number of bytes to copy \*****************************************************************************/ inline void MemCopyWC( void* dst, const void* src, const size_t bytes ) { #if defined ( _MSC_VER ) const __m128i s_SSE2CmpMask = _mm_setr_epi8( 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 ); const __m128i* pMMSrc = reinterpret_cast(src); __m128i* pMMDest = reinterpret_cast<__m128i*>(dst); size_t count = bytes; size_t cnt = 0; __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; // if size > 16 align destination and move non-temporally if (count >= INSTR_WIDTH_128) { // align destination to 16 if necessary UINT32 align = (UINT32)((UINT_PTR)pMMDest & TAIL_SIZE); if (align != 0) { // move alignment through a masked non-temporal move const char* pSrc = reinterpret_cast(pMMSrc); char* pDst = reinterpret_cast(pMMDest); align = INSTR_WIDTH_128 - align; char shiftCnt = (char)(INSTR_WIDTH_128 - align - 1); __m128i shiftMask = _mm_set1_epi8(shiftCnt); __m128i mask = _mm_cmpgt_epi8(s_SSE2CmpMask, shiftMask); __m128i val = _mm_loadu_si128(pMMSrc); _mm_maskmoveu_si128(val, mask, pDst); pSrc += align; pDst += align; pMMSrc = reinterpret_cast(pSrc); pMMDest = reinterpret_cast<__m128i*>(pDst); } count -= align; // take off the alignment from size // check source alignment if ((UINT_PTR)pMMSrc & TAIL_SIZE) { // copy un-aligned by tiers cnt = count >> DUAL_CACHE_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_loadu_si128(pMMSrc); xmm1 = _mm_loadu_si128(pMMSrc + 1); xmm2 = _mm_loadu_si128(pMMSrc + 2); xmm3 = _mm_loadu_si128(pMMSrc + 3); xmm4 = _mm_loadu_si128(pMMSrc + 4); xmm5 = _mm_loadu_si128(pMMSrc + 5); xmm6 = _mm_loadu_si128(pMMSrc + 6); xmm7 = _mm_loadu_si128(pMMSrc + 7); pMMSrc += 8; _mm_stream_si128(pMMDest, xmm0); _mm_stream_si128(pMMDest + 1, xmm1); _mm_stream_si128(pMMDest + 2, xmm2); _mm_stream_si128(pMMDest + 3, xmm3); _mm_stream_si128(pMMDest + 4, xmm4); _mm_stream_si128(pMMDest + 5, xmm5); _mm_stream_si128(pMMDest + 6, xmm6); _mm_stream_si128(pMMDest + 7, xmm7); pMMDest += 8; } count &= TIERED_TAIL; if (count != 0) { cnt = count >> INSTR_128_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_loadu_si128(pMMSrc); pMMSrc += 1; _mm_stream_si128(pMMDest, xmm0); pMMDest += 1; } } } else { // copy aligned by tiers cnt = count >> DUAL_CACHE_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_load_si128(pMMSrc); xmm1 = _mm_load_si128(pMMSrc + 1); xmm2 = _mm_load_si128(pMMSrc + 2); xmm3 = _mm_load_si128(pMMSrc + 3); xmm4 = _mm_load_si128(pMMSrc + 4); xmm5 = _mm_load_si128(pMMSrc + 5); xmm6 = _mm_load_si128(pMMSrc + 6); xmm7 = _mm_load_si128(pMMSrc + 7); pMMSrc += 8; _mm_stream_si128(pMMDest, xmm0); _mm_stream_si128(pMMDest + 1, xmm1); _mm_stream_si128(pMMDest + 2, xmm2); _mm_stream_si128(pMMDest + 3, xmm3); _mm_stream_si128(pMMDest + 4, xmm4); _mm_stream_si128(pMMDest + 5, xmm5); _mm_stream_si128(pMMDest + 6, xmm6); _mm_stream_si128(pMMDest + 7, xmm7); pMMDest += 8; } count &= TIERED_TAIL; if (count != 0) { cnt = count >> INSTR_128_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_load_si128(pMMSrc); pMMSrc += 1; _mm_stream_si128(pMMDest, xmm0); pMMDest += 1; } } } } // handle tail copy as a fallthrough count &= TAIL_SIZE; if (count != 0) { cnt = count >> DWORD_SHIFT; DWORD* pDst = reinterpret_cast(pMMDest); const DWORD* pSrc = reinterpret_cast(pMMSrc); for (UINT32 i = 0; i < cnt; i += 1) { *pDst = *pSrc; pDst += 1; pSrc += 1; } cnt = count & BYTE_TAIL; BYTE* bDst = reinterpret_cast(pDst); const BYTE* bSrc = reinterpret_cast(pSrc); for (UINT32 i = 0; i < cnt; i += 1) { *bDst = *bSrc; bDst += 1; bSrc += 1; } } #else // #if defined ( _MSC_VER ) // Linux projects do not support standard types or memcpy_s ::memcpy_s(dst, bytes, src, bytes); #endif } /*****************************************************************************\ Inline Function: ScalarSwapBytes Description: Helper function for MemCopySwapBytes \*****************************************************************************/ inline void ScalarSwapBytes( __m128i** dst, const __m128i** src, const size_t byteCount, const unsigned int swapbytes) { switch (swapbytes) { case 2: { WORD* wDst = reinterpret_cast(*dst); const WORD* wSrc = reinterpret_cast(*src); for (UINT32 i = 0; i < byteCount / 2; i += 1) { WORD tmp = *wSrc; *wDst = (tmp >> 8) | (tmp << 8); wDst += 1; wSrc += 1; } *src = reinterpret_cast(wSrc); *dst = reinterpret_cast<__m128i*>(wDst); } break; case 4: { DWORD* dwDst = reinterpret_cast(*dst); const DWORD* dwSrc = reinterpret_cast(*src); for (UINT32 i = 0; i < byteCount / 4; i += 1) { DWORD tmp = *dwSrc; *dwDst = (tmp >> 24) | (tmp << 24) | ((tmp & 0x0000FF00) << 8) | ((tmp & 0x00FF0000) >> 8); dwDst += 1; dwSrc += 1; } *src = reinterpret_cast(dwSrc); *dst = reinterpret_cast<__m128i*>(dwDst); } break; default: // should not occur BYTE* bDst = reinterpret_cast(*dst); const BYTE* bSrc = reinterpret_cast(*src); ::memcpy_s(bDst, byteCount, bSrc, byteCount); *src = reinterpret_cast(bSrc + byteCount); *dst = reinterpret_cast<__m128i*>(bDst + byteCount); } } /*****************************************************************************\ Inline Function: MemCopySwapBytes Description: Memory copy with swapped byte order, 2 and 4 byte elements only Input: dst - pointer to write-combined destination buffer src - pointer to source buffer bytes - number of bytes to copy swapbytes - granularity of elements to swap \*****************************************************************************/ inline void MemCopySwapBytes( void* dst, const void* src, const size_t bytes, const unsigned int swapbytes) { const __m128i* pMMSrc = reinterpret_cast(src); __m128i* pMMDest = reinterpret_cast<__m128i*>(dst); size_t count = bytes; size_t cnt = 0; __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; // 2 byte shuffle const __m128i wordMask = _mm_setr_epi8( 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e); // 4 byte shuffle const __m128i dwordMask = _mm_setr_epi8( 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c); // SSE3 support required CPU_INSTRUCTION_LEVEL cpuInstructionLevel = GetCpuInstructionLevel(); if (cpuInstructionLevel < CPU_INSTRUCTION_LEVEL_SSE3) { ScalarSwapBytes(&pMMDest, &pMMSrc, count, swapbytes); return; } // only handle 2 and 4 bytes swapping if (swapbytes != 2 && swapbytes != 4) { MemCopy(pMMDest, pMMSrc, count); return; } // when size is < 16 rely, must use scalar swap if (count < INSTR_WIDTH_128) { ScalarSwapBytes(&pMMDest, &pMMSrc, count, swapbytes); } else { const __m128i shuffleMask = (swapbytes == 2) ? wordMask : dwordMask; // handle un-aligned tiered copy up to 2 cache lines if (count < 2 * CACHE_LINE_SIZE) { cnt = count >> INSTR_128_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_loadu_si128(pMMSrc); pMMSrc += 1; xmm0 = _mm_shuffle_epi8(xmm0, shuffleMask); _mm_storeu_si128(pMMDest, xmm0); pMMDest += 1; } } // handle aligned copy for > 2 cache lines else { // align destination to 16 if necessary UINT32 align = (UINT32)((UINT_PTR)pMMDest & TAIL_SIZE); if (align != 0) { align = INSTR_WIDTH_128 - align; cnt = align >> DWORD_SHIFT; ScalarSwapBytes(&pMMDest, &pMMSrc, cnt * sizeof(DWORD), swapbytes); cnt = align & BYTE_TAIL; // only words should remain, not bytes if (cnt > 0) { ASSERT(cnt % 2 == 0); ASSERT(swapbytes == 2); ScalarSwapBytes(&pMMDest, &pMMSrc, cnt, swapbytes); } } count -= align; // take off the alignment from size // check source alignment if ((UINT_PTR)pMMSrc & TAIL_SIZE) { // copy un-aligned by tiers cnt = count >> DUAL_CACHE_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_loadu_si128(pMMSrc); xmm1 = _mm_loadu_si128(pMMSrc + 1); xmm2 = _mm_loadu_si128(pMMSrc + 2); xmm3 = _mm_loadu_si128(pMMSrc + 3); xmm4 = _mm_loadu_si128(pMMSrc + 4); xmm5 = _mm_loadu_si128(pMMSrc + 5); xmm6 = _mm_loadu_si128(pMMSrc + 6); xmm7 = _mm_loadu_si128(pMMSrc + 7); pMMSrc += 8; xmm0 = _mm_shuffle_epi8(xmm0, shuffleMask); xmm1 = _mm_shuffle_epi8(xmm1, shuffleMask); xmm2 = _mm_shuffle_epi8(xmm2, shuffleMask); xmm3 = _mm_shuffle_epi8(xmm3, shuffleMask); xmm4 = _mm_shuffle_epi8(xmm4, shuffleMask); xmm5 = _mm_shuffle_epi8(xmm5, shuffleMask); xmm6 = _mm_shuffle_epi8(xmm6, shuffleMask); xmm7 = _mm_shuffle_epi8(xmm7, shuffleMask); _mm_store_si128(pMMDest, xmm0); _mm_store_si128(pMMDest + 1, xmm1); _mm_store_si128(pMMDest + 2, xmm2); _mm_store_si128(pMMDest + 3, xmm3); _mm_store_si128(pMMDest + 4, xmm4); _mm_store_si128(pMMDest + 5, xmm5); _mm_store_si128(pMMDest + 6, xmm6); _mm_store_si128(pMMDest + 7, xmm7); pMMDest += 8; } count &= TIERED_TAIL; if (count != 0) { cnt = count >> INSTR_128_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_loadu_si128(pMMSrc); pMMSrc += 1; xmm0 = _mm_shuffle_epi8(xmm0, shuffleMask); _mm_store_si128(pMMDest, xmm0); pMMDest += 1; } } } else { // copy aligned by tiers cnt = count >> DUAL_CACHE_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_load_si128(pMMSrc); xmm1 = _mm_load_si128(pMMSrc + 1); xmm2 = _mm_load_si128(pMMSrc + 2); xmm3 = _mm_load_si128(pMMSrc + 3); xmm4 = _mm_load_si128(pMMSrc + 4); xmm5 = _mm_load_si128(pMMSrc + 5); xmm6 = _mm_load_si128(pMMSrc + 6); xmm7 = _mm_load_si128(pMMSrc + 7); pMMSrc += 8; xmm0 = _mm_shuffle_epi8(xmm0, shuffleMask); xmm1 = _mm_shuffle_epi8(xmm1, shuffleMask); xmm2 = _mm_shuffle_epi8(xmm2, shuffleMask); xmm3 = _mm_shuffle_epi8(xmm3, shuffleMask); xmm4 = _mm_shuffle_epi8(xmm4, shuffleMask); xmm5 = _mm_shuffle_epi8(xmm5, shuffleMask); xmm6 = _mm_shuffle_epi8(xmm6, shuffleMask); xmm7 = _mm_shuffle_epi8(xmm7, shuffleMask); _mm_store_si128(pMMDest, xmm0); _mm_store_si128(pMMDest + 1, xmm1); _mm_store_si128(pMMDest + 2, xmm2); _mm_store_si128(pMMDest + 3, xmm3); _mm_store_si128(pMMDest + 4, xmm4); _mm_store_si128(pMMDest + 5, xmm5); _mm_store_si128(pMMDest + 6, xmm6); _mm_store_si128(pMMDest + 7, xmm7); pMMDest += 8; } count &= TIERED_TAIL; if (count != 0) { cnt = count >> INSTR_128_SHIFT; for (UINT32 i = 0; i < cnt; i += 1) { xmm0 = _mm_load_si128(pMMSrc); pMMSrc += 1; xmm0 = _mm_shuffle_epi8(xmm0, shuffleMask); _mm_store_si128(pMMDest, xmm0); pMMDest += 1; } } } } // handle tail copy as a fallthrough count &= TAIL_SIZE; if (count != 0) { cnt = count >> DWORD_SHIFT; ScalarSwapBytes(&pMMDest, &pMMSrc, cnt * sizeof(DWORD), swapbytes); cnt = count & BYTE_TAIL; // only words should remain, not bytes if (cnt > 0) { ASSERT(cnt % 2 == 0); ASSERT(swapbytes == 2); ScalarSwapBytes(&pMMDest, &pMMSrc, cnt, swapbytes); } } } } /*****************************************************************************\ Inline Function: SafeMemSet Description: Exception Handler Memory Set function \*****************************************************************************/ inline void SafeMemSet( void* dst, const int data, const size_t bytes ) { #if defined(_DEBUG) && defined(ISTDLIB_KMD) __try #endif { ::memset( dst, data, bytes ); } #if defined(_DEBUG) && defined(ISTDLIB_KMD) // catch exceptions here so they are easily debugged __except(1) { ASSERT(0); } #endif } /*****************************************************************************\ Inline Function: SafeMemCompare Description: Exception Handler Memory Compare function \*****************************************************************************/ inline int SafeMemCompare( const void* dst, const void* src, const size_t bytes ) { #if defined(_DEBUG) && defined(ISTDLIB_KMD) __try #endif { return ::memcmp( dst, src, bytes ); } #if defined(_DEBUG) && defined(ISTDLIB_KMD) // catch exceptions here so they are easily debugged __except(1) { ASSERT(0); return -1; } #endif } /*****************************************************************************\ Inline Function: SafeMemMove Description: copies "bytes" of data from src to dst. dst is not corrupted if src and dst blocks of data overlap. Input: dst - pointer to destination buffer src - pointer to source buffer bytes - number of bytes to copy \*****************************************************************************/ inline void SafeMemMove( void *dst, const void *src, const size_t bytes ) { if( dst!=src ) { if( src>dst && bytes ) { size_t t = 0; do { static_cast< unsigned char* >( dst )[t] = static_cast< const unsigned char* >( src )[t]; } while( ++t != bytes ); } else { size_t t = bytes-1; do { static_cast< unsigned char* >( dst )[t] = static_cast< const unsigned char* >( src )[t]; } while( t-- != 0 ); } } } /*****************************************************************************\ MACROS: EMIT_R_MR Example: movntdqa xmm1, xmmword ptr [eax] EMIT_R_MR_OFFSET Example: movntdqa xmm1, xmmword ptr [eax + 0x10] Description: Used to encode SSE4.1 instructions with parametrs \*****************************************************************************/ #define EMIT_R_MR(OPCODE, X, Y ) \ OPCODE \ __asm _emit (0x00 + X*8 + Y) #define EMIT_R_MR_OFFSET(OPCODE, X, Y, OFFSET) \ OPCODE \ __asm _emit (0x80 + X*8 + Y) \ __asm _emit (OFFSET&0xFF) \ __asm _emit ((OFFSET>>8)&0xFF) \ __asm _emit ((OFFSET>>16)&0xFF) \ __asm _emit ((OFFSET>>24)&0xFF) /*****************************************************************************\ MACROS: REG_XXX Description: Define CPU General Purpose and XMM Register Indices These MACROS are to be replaced with instrinics available with .NET 2008 \*****************************************************************************/ #if defined( _MSC_VER ) #define REG_EAX 0x00 #define REG_ECX 0x01 #define REG_EDX 0x02 #define REG_EBX 0x03 #define REG_ESP 0x04 #define REG_EBP 0x05 #define REG_ESI 0x06 #define REG_EDI 0x07 #define REG_XMM0 0x00 #define REG_XMM1 0x01 #define REG_XMM2 0x02 #define REG_XMM3 0x03 #define REG_XMM4 0x04 #define REG_XMM5 0x05 #define REG_XMM6 0x06 #define REG_XMM7 0x07 #endif //#if defined( _MSC_VER ) /*****************************************************************************\ MACROS: MOVNTDQA_OP MOVNTDQA_R_MR MOVNTDQA_R_MRB Description: Used to emit SSE4_1 movntdqa (streaming load) instructions SRC - XMM Register, destination data is to be stored DST - General Purpose Register containing source address OFFSET - Offset to be added to the source address \*****************************************************************************/ #define MOVNTDQA_OP \ _asm _emit 0x66 \ _asm _emit 0x0F \ _asm _emit 0x38 \ _asm _emit 0x2A #define MOVNTDQA_R_MR(DST, SRC) \ EMIT_R_MR(MOVNTDQA_OP, DST, SRC) #define MOVNTDQA_R_MR_OFFSET(DST, SRC, OFFSET) \ EMIT_R_MR_OFFSET(MOVNTDQA_OP, DST, SRC, OFFSET) /*****************************************************************************\ Inline Function: FastBlockCopyFromUSWC_SSE4_1_movntdqa_movdqa Description: Fast copy from USWC memory to cacheable system memory Input: dst - 16-byte aligned pointer to (cacheable) destination buffer src - 16-byte(req)/64-byte(optimal) aligned pointer to (USWC) source buffer \*****************************************************************************/ #if defined( _MSC_VER ) && !defined (_WIN64) __forceinline void __fastcall FastBlockCopyFromUSWC_SSE4_1_movntdqa_movdqa( void* dst, const void* src ) { __asm { ;Store the orginal source start address mov edx, src ;Store the dest address mov ecx, dst align 16 ; Load data from source buffer ; Streaming loads from the same cache line should be grouped together ; and not be interleaved with: a) Writes or non-streaming loads or ; b) Streaming loads from other cache lines (strided accesses) ; movntdqa xmm0, xmmword ptr [edx] MOVNTDQA_R_MR(REG_XMM0, REG_EDX) ; movntdqa xmm1, xmmword ptr [edx+16] MOVNTDQA_R_MR_OFFSET(REG_XMM1, REG_EDX, 16) ; movntdqa xmm2, xmmword ptr [edx+32] MOVNTDQA_R_MR_OFFSET(REG_XMM2, REG_EDX, 32) ; movntdqa xmm3, xmmword ptr [edx+48] MOVNTDQA_R_MR_OFFSET(REG_XMM3, REG_EDX, 48) ; Save data in destination buffer. movdqa xmmword ptr [ecx], xmm0 movdqa xmmword ptr [ecx+16], xmm1 movdqa xmmword ptr [ecx+32], xmm2 movdqa xmmword ptr [ecx+48], xmm3 } } // FastMemCopy_SSE4_1_movntdqa_movdqa() #endif //#if defined( _MSC_VER ) && !defined (_WIN64) /*****************************************************************************\ Inline Function: FastBlockCopyFromUSWC_SSE4_1_movntdqa_movdqu Description: Fast copy from USWC memory (DHWORD in size) to cacheable system memory Input: dst - 16-byte (unaligned) pointer to (cacheable) destination buffer src - 16-byte(req)/64-byte(optimal) aligned pointer to (USWC) source buffer \*****************************************************************************/ #if defined ( _MSC_VER ) && !defined(_WIN64) __forceinline void __fastcall FastBlockCopyFromUSWC_SSE4_1_movntdqa_movdqu(void* dst, const void* src ) { __asm { ;Store the orginal source start address mov edx, src ;Store the dest address mov ecx, dst align 16 ; Load data from source buffer ; Streaming loads from the same cache line should be grouped together ; and not be interleaved with: a) Writes or non-streaming loads or ; b) Streaming loads from other cache lines (strided accesses) ; movntdqa xmm0, xmmword ptr [edx] MOVNTDQA_R_MR(REG_XMM0, REG_EDX) ; movntdqa xmm1, xmmword ptr [edx+16] MOVNTDQA_R_MR_OFFSET(REG_XMM1, REG_EDX, 16) ; movntdqa xmm2, xmmword ptr [edx+32] MOVNTDQA_R_MR_OFFSET(REG_XMM2, REG_EDX, 32) ; movntdqa xmm3, xmmword ptr [edx+48] MOVNTDQA_R_MR_OFFSET(REG_XMM3, REG_EDX, 48) ; Copy data in destination buffer. movdqu xmmword ptr [ecx], xmm0 movdqu xmmword ptr [ecx+16], xmm1 movdqu xmmword ptr [ecx+32], xmm2 movdqu xmmword ptr [ecx+48], xmm3 } } // FastMemCopy_SSE4_1_movntdqa_movdqu() #endif // #if defined( _MSC_VER ) && !defined (_WIN64) inline void FastMemCopyFromWC( void* dst, const void* src, const size_t bytes, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ) { #if defined( _MSC_VER ) && (!defined (_WIN64) || defined ( _In_ ) ) || defined (__GNUC__) if( cpuInstructionLevel >= CPU_INSTRUCTION_LEVEL_SSE4_1 ) { // Cache pointers to memory BYTE* p_dst = (BYTE*)dst; BYTE* p_src = (BYTE*)src; size_t count = bytes; if( count >= sizeof(DHWORD) ) { //Streaming Load must be 16-byte aligned but should //be 64-byte aligned for optimal performance const size_t doubleHexWordAlignBytes = GetAlignmentOffset( p_src, sizeof(DHWORD) ); // Copy portion of the source memory that is not aligned if( doubleHexWordAlignBytes ) { MemCopy( p_dst, p_src, doubleHexWordAlignBytes ); p_dst += doubleHexWordAlignBytes; p_src += doubleHexWordAlignBytes; count -= doubleHexWordAlignBytes; } ASSERT( IsAligned( p_src, sizeof(DHWORD) ) == true ); // Get the number of bytes to be copied (rounded down to nearets DHWORD) const size_t DoubleHexWordsToCopy = count / sizeof(DHWORD); if( DoubleHexWordsToCopy ) { // Determine if the destination address is aligned const bool isDstDoubleQuadWordAligned = IsAligned( p_dst, sizeof(DQWORD) ); #if defined(_WIN64) || defined(__GNUC__) __m128i* pMMSrc = (__m128i*)(p_src); __m128i* pMMDest = reinterpret_cast<__m128i*>(p_dst); __m128i xmm0, xmm1, xmm2, xmm3; #endif if( isDstDoubleQuadWordAligned ) { #if defined(__GNUC__) // Sync the WC memory data before issuing the MOVNTDQA instruction. _mm_mfence(); #endif for( size_t i=0; i 0 ); } /*****************************************************************************\ Inline Function: FastCpuSet Description: Intel C++ Compiler CPU Blit function Parameters: BYTE* dst - destination pointer const DWORD dstPitch - pitch to increment destination pointer per count BYTE* src - source pointer const DWORD srcPitch - pitch to increment source pointer per count const DWORD stride - stride of data to copy per count, in bytes DWORD count - number of iterations to copy data \*****************************************************************************/ inline void FastCpuSet( BYTE* dst, const DWORD dstPitch, const DWORD value, const DWORD stride, DWORD count ) { do { SafeMemSet( dst, value, stride ); dst += dstPitch; } while( --count > 0 ); } /*****************************************************************************\ Inline Function: FastCpuBltFromUSWC Description: Intel C++ Compiler CPU Blit function from non-temporal to temporal memory This function is optimized using SSE4 instructions which use accelerated write-combined loads that bypass the cache. Parameters: BYTE* dst - destination pointer (temporal) const DWORD dstPitch - pitch to increment destination pointer per count BYTE* src - source pointer (non-temporal) const DWORD srcPitch - pitch to increment source pointer per count const DWORD stride - stride of data to copy per count, in bytes DWORD count - number of iterations to copy data CPU_INSTRUCTION_LEVEL level - cpu instruction level (SSE support level) \*****************************************************************************/ #if defined ( _MSC_VER ) inline void FastCpuBltFromUSWC( BYTE* dst, const DWORD dstPitch, BYTE* src, const DWORD srcPitch, const DWORD stride, DWORD count, CPU_INSTRUCTION_LEVEL level) { #ifndef _WIN64 //back up the XMM registers just in case __declspec( align(16) ) BYTE backUpRegisters[16*4]; void *tempPtr = (void *) backUpRegisters; __asm mov ecx, tempPtr __asm movdqa xmmword ptr [ecx + 16*0], xmm0 __asm movdqa xmmword ptr [ecx + 16*1], xmm1 __asm movdqa xmmword ptr [ecx + 16*2], xmm2 __asm movdqa xmmword ptr [ecx + 16*3], xmm3 #endif //_WIN64 do { iSTD::FastMemCopyFromWC( dst, src, stride, level ); dst += dstPitch; src += srcPitch; } while( --count > 0 ); #ifndef _WIN64 #if defined ( _MSC_VER ) __asm mov ecx, tempPtr __asm movdqa xmm0, xmmword ptr [ecx + 16*0] __asm movdqa xmm1, xmmword ptr [ecx + 16*1] __asm movdqa xmm2, xmmword ptr [ecx + 16*2] __asm movdqa xmm3, xmmword ptr [ecx + 16*3] #endif #endif //_WIN64 } #endif /*****************************************************************************\ Inline Function: FindWordBufferMinMax Description: Finds the min and max unsigned 16-bit values in the buffer Input: WORD* pBuffer - pointer to 16-bit buffer const DWORD bytes - size of buffer in bytes Output: WORD &min - minimum 16-bit value WORD &max - maximum 16-bit value \*****************************************************************************/ inline void FindWordBufferMinMax( WORD* pBuffer, const DWORD bytes, WORD &min, WORD &max ) { PrefetchBuffer( (BYTE*)pBuffer, bytes ); WORD wValue = 0; WORD wMinValue = 0xffff; WORD wMaxValue = 0x0000; size_t count = bytes / sizeof(WORD); size_t i = 0; if( IsAligned( pBuffer, sizeof(WORD) ) ) { const size_t DoubleQuadWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DQWORD); const size_t WordsPerPrefetch = sizeof(PREFETCH) / sizeof(WORD); const size_t WordsPerDoubleQuadWord = sizeof(DQWORD) / sizeof(WORD); Prefetch( (BYTE*)pBuffer + sizeof(PREFETCH) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Find min/max per cacheline of values if( count >= WordsPerDoubleQuadWord ) { const size_t doubleQuadwordAlignWords = GetAlignmentOffset( pBuffer, sizeof(DQWORD) ) / sizeof(WORD); // If pBuffer is not double-quadword aligned then process // until aligned if( doubleQuadwordAlignWords ) { for( i = 0; i < doubleQuadwordAlignWords; i++ ) { wValue = *pBuffer++; wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } count -= doubleQuadwordAlignWords; } // Find min/max per cacheline of values if( count >= WordsPerDoubleQuadWord ) { __m128i mValue128i; // Need to convert unsigned values to signed values // since min/max is signed op __m128i mSignedScale128i = _mm_set1_epi16((WORD)0x8000); // Signed min/max initialization __m128i mMinValue128i = _mm_set1_epi16(wMinValue-(WORD)0x8000); __m128i mMaxValue128i = _mm_set1_epi16(wMaxValue-(WORD)0x8000); while( count >= WordsPerPrefetch ) { Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Process cacheline values per pass count -= WordsPerPrefetch; for( i = 0; i < DoubleQuadWordsPerPrefetch; i++ ) { // Get double-quadword values mValue128i = *(__m128i*)pBuffer; pBuffer += WordsPerDoubleQuadWord; // Make values signed mValue128i = _mm_sub_epi16( mValue128i, mSignedScale128i ); // Determine parallel min/max mMinValue128i = _mm_min_epi16( mMinValue128i, mValue128i ); mMaxValue128i = _mm_max_epi16( mMaxValue128i, mValue128i ); } } // Process double-quadword values per pass for remainder while( count >= WordsPerDoubleQuadWord ) { // Process double-quadword values per pass count -= WordsPerDoubleQuadWord; // Get double-quadword values mValue128i = *(__m128i*)pBuffer; pBuffer += WordsPerDoubleQuadWord; // Make values signed mValue128i = _mm_sub_epi16( mValue128i, mSignedScale128i ); // Determine parallel min/max mMinValue128i = _mm_min_epi16( mMinValue128i, mValue128i ); mMaxValue128i = _mm_max_epi16( mMaxValue128i, mValue128i ); } // Determine wMinValue // Make values unsigned mMinValue128i = _mm_add_epi16( mMinValue128i, mSignedScale128i ); // Extract each value in double-quadword to find minimum // for( i = 0; i < WordsPerDoubleQuadWord; i++ ) wValue = (WORD)_mm_extract_epi16( mMinValue128i, 0 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 1 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 2 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 3 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 4 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 5 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 6 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 7 ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Make values unsigned mMaxValue128i = _mm_add_epi16( mMaxValue128i, mSignedScale128i ); // Extract each value in double-quadword to find maximum // for( i = 0; i < WordsPerDoubleQuadWord; i++ ) wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 0 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 1 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 2 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 3 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 4 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 5 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 6 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 7 ); wMaxValue = Max( wMaxValue, wValue ); } // if( count >= WordsPerDoubleQuadWord ) } // if( count >= WordsPerDoubleQuadWord ) } #ifndef _WIN64 else // if( IsAligned( pBuffer, sizeof(WORD) ) ) { const size_t QuadWordsPerCacheline = sizeof(CACHELINE) / sizeof(QWORD); const size_t WordsPerCacheline = sizeof(CACHELINE) / sizeof(WORD); const size_t WordsPerQuadWord = sizeof(QWORD) / sizeof(WORD); Prefetch( (BYTE*)pBuffer + sizeof(CACHELINE) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(CACHELINE) ); if( count >= WordsPerQuadWord ) { __m64 mValue64; // Need to convert unsigned values to signed values // since min/max is signed op __m64 mSignedScale64 = _mm_set1_pi16((WORD)0x8000); // Signed min/max initialization __m64 mMinValue64 = _mm_set1_pi16(wMinValue-(WORD)0x8000); __m64 mMaxValue64 = _mm_set1_pi16(wMaxValue-(WORD)0x8000); // Find min/max per cacheline of values while( count >= WordsPerCacheline ) { Prefetch( (BYTE*)pBuffer + sizeof(CACHELINE) ); // Process cacheline values per pass count -= WordsPerCacheline; for( i = 0; i < QuadWordsPerCacheline; i++ ) { // Get quadword values mValue64 = *(__m64*)pBuffer; pBuffer += WordsPerQuadWord; // Make values signed mValue64 = _mm_sub_pi16( mValue64, mSignedScale64 ); // Determine parallel min/max mMinValue64 = _mm_min_pi16( mMinValue64, mValue64 ); mMaxValue64 = _mm_max_pi16( mMaxValue64, mValue64 ); } } // Process quadword values per pass for remainder while( count >= WordsPerQuadWord ) { // Process quadword values per pass count -= WordsPerQuadWord; // Get quadword values mValue64 = *(__m64*)pBuffer; pBuffer += WordsPerQuadWord; // Make values signed mValue64 = _mm_sub_pi16( mValue64, mSignedScale64 ); // Determine parallel min/max mMinValue64 = _mm_min_pi16( mMinValue64, mValue64 ); mMaxValue64 = _mm_max_pi16( mMaxValue64, mValue64 ); } // Determine wMinValue // Make values unsigned mMinValue64 = _mm_add_pi16( mMinValue64, mSignedScale64 ); // Extract each value in quadword to find minimum // for( i = 0; i < WordsPerQuadWord; i++ ) wValue = (WORD)_mm_extract_pi16( mMinValue64, 0 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMinValue64, 1 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMinValue64, 2 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMinValue64, 3 ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Make values unsigned mMaxValue64 = _mm_add_pi16( mMaxValue64, mSignedScale64 ); // Extract each value in quadword to find maximum // for( i = 0; i < WordsPerQuadWord; i++ ) wValue = (WORD)_mm_extract_pi16( mMaxValue64, 0 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMaxValue64, 1 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMaxValue64, 2 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMaxValue64, 3 ); wMaxValue = Max( wMaxValue, wValue ); _mm_empty(); } // if( count >= WordsPerQuadWord ) } #endif // Find min/max per value while( count > 0 ) { count -= 1; wValue = *pBuffer++; wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } min = wMinValue; max = wMaxValue; } /*****************************************************************************\ Inline Function: FindWordBufferMinMaxRestart Description: Finds the min and max unsigned 32-bit values in the buffer Excludes a restart value from min or max values Input: WORD* pBuffer - pointer to 32-bit buffer const DWORD bytes - size of buffer in bytes const WORD restart - restart index to ignore cpuInstructionLevel - indicates if SSE_4.1 is available Output: WORD &min - minimum 32-bit value WORD &max - maximum 32-bit value \*****************************************************************************/ inline void FindWordBufferMinMaxRestart( WORD* pBuffer, const DWORD bytes, const WORD restart, WORD &min, WORD &max, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ) { // PrefetchBuffer( (BYTE*)pBuffer, bytes ); WORD wValue = 0; WORD wMinValue = 0xffff; WORD wMaxValue = 0x0000; size_t count = bytes / sizeof(WORD); #ifdef USE_SSE4_1 size_t i = 0; if( IsAligned( pBuffer, sizeof(WORD) ) && cpuInstructionLevel >= CPU_INSTRUCTION_LEVEL_SSE4_1 ) { const DWORD DoubleQuadWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DQWORD); const DWORD WordsPerPrefetch = sizeof(PREFETCH) / sizeof(WORD); const DWORD WordsPerDoubleQuadWord = sizeof(DQWORD) / sizeof(WORD); Prefetch( (BYTE*)pBuffer + sizeof(PREFETCH) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Find min/max per cacheline of values if( count >= WordsPerDoubleQuadWord ) { const size_t doubleQuadwordAlignWords = GetAlignmentOffset( pBuffer, sizeof(DQWORD) ) / sizeof(WORD); // If pBuffer is not double-quadword aligned then process // until aligned if( doubleQuadwordAlignWords ) { for( i = 0; i < doubleQuadwordAlignWords; i++ ) { wValue = *pBuffer++; if (wValue == restart) { continue; } wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } count -= doubleQuadwordAlignWords; } // Find min/max per cacheline of values if( count >= WordsPerDoubleQuadWord ) { __m128i mInput, mRestarts, mMask; __m128i mAll_ones; __m128i mMinValue128i, mMaxValue128i; // This is just used for andnot mInput mAll_ones.m128i_u64[0] = 0xFFFFFFFFFFFFFFFF; mAll_ones.m128i_u64[1] = 0xFFFFFFFFFFFFFFFF; // start with really high min and really low max // What should happen if all values are restart? mMinValue128i.m128i_u64[0] = 0xFFFFFFFFFFFFFFFF; mMinValue128i.m128i_u64[1] = 0xFFFFFFFFFFFFFFFF; mMaxValue128i.m128i_u64[0] = 0x0000000000000000; mMaxValue128i.m128i_u64[1] = 0x0000000000000000; // Initialize register used for testing for restart index. mRestarts.m128i_u64[0] = mRestarts.m128i_u64[1] = (((UINT64) restart) << 48) | (((UINT64) restart) << 32) | (((UINT64) restart) << 16) | ((UINT64) restart); while( count >= WordsPerPrefetch ) { Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Process cacheline values per pass count -= WordsPerPrefetch; for( i = 0; i < DoubleQuadWordsPerPrefetch; i++ ) { // Get double-quadword values mInput = *(__m128i*)pBuffer; pBuffer += WordsPerDoubleQuadWord; // Make mask of non-restart_index fields mMask = _mm_andnot_si128(_mm_cmpeq_epi16(mInput, mRestarts), mAll_ones); // Copy minimum and maximum fields for non-restarts mMinValue128i = _mm_blendv_epi8(mMinValue128i, _mm_min_epu16(mMinValue128i, mInput), mMask ); mMaxValue128i = _mm_blendv_epi8(mMaxValue128i, _mm_max_epu16(mMaxValue128i, mInput), mMask ); } } // Process double-quadword values per pass for remainder while( count >= WordsPerDoubleQuadWord ) { // Process double-quadword values per pass count -= WordsPerDoubleQuadWord; // Get double-quadword values mInput = *(__m128i*)pBuffer; pBuffer += WordsPerDoubleQuadWord; // Make mask of non-restart_index fields mMask = _mm_andnot_si128(_mm_cmpeq_epi16(mInput, mRestarts), mAll_ones); // Copy minimum and maximum fields for non-restarts mMinValue128i = _mm_blendv_epi8(mMinValue128i, _mm_min_epu16(mMinValue128i, mInput), mMask ); mMaxValue128i = _mm_blendv_epi8(mMaxValue128i, _mm_max_epu16(mMaxValue128i, mInput), mMask ); } // Determine wMinValue // Extract each value in double-quadword to find minimum // for( i = 0; i < WordsPerDoubleQuadWord; i++ ) wValue = (WORD)_mm_extract_epi16( mMinValue128i, 0 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 1 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 2 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 3 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 4 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 5 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 6 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 7 ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Extract each value in double-quadword to find maximum // for( i = 0; i < WordsPerDoubleQuadWord; i++ ) wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 0 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 1 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 2 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 3 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 4 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 5 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 6 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 7 ); wMaxValue = Max( wMaxValue, wValue ); } // if( count >= WordsPerDoubleQuadWord ) } // if( count >= WordsPerDoubleQuadWord ) } #endif // USE_SSE4_1 // Find min/max per value while( count > 0 ) { count -= 1; wValue = *pBuffer++; if (wValue == restart) { continue; } wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } min = wMinValue; max = wMaxValue; } /*****************************************************************************\ Inline Function: FindDWordBufferMinMax Description: Finds the min and max unsigned 32-bit values in the buffer Input: DWORD* pBuffer - pointer to 32-bit buffer const DWORD bytes - size of buffer in bytes Output: DWORD &min - minimum 32-bit value DWORD &max - maximum 32-bit value \*****************************************************************************/ inline void FindDWordBufferMinMax( DWORD* pBuffer, const DWORD bytes, DWORD &min, DWORD &max ) { PrefetchBuffer( (BYTE*)pBuffer, bytes ); DWORD wValue = 0; DWORD wMinValue = 0xffffffff; DWORD wMaxValue = 0x00000000; DWORD count = bytes / sizeof(DWORD); DWORD i = 0; if( IsAligned( pBuffer, sizeof(DWORD) ) ) { const DWORD DoubleQuadWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DQWORD); const DWORD DWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DWORD); const DWORD DWordsPerDoubleQuadWord = sizeof(DQWORD) / sizeof(DWORD); Prefetch( (BYTE*)pBuffer + sizeof(PREFETCH) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Find min/max per cacheline of values if( count >= DWordsPerDoubleQuadWord ) { const DWORD doubleQuadwordAlignWords = GetAlignmentOffset( pBuffer, sizeof(DQWORD) ) / sizeof(DWORD); // If pBuffer is not double-quadword aligned then process // until aligned if( doubleQuadwordAlignWords ) { for( i = 0; i < doubleQuadwordAlignWords; i++ ) { wValue = *pBuffer++; wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } count -= doubleQuadwordAlignWords; } // Find min/max per cacheline of values if( count >= DWordsPerPrefetch ) { __m128i mValue128i; __m128 mValue128; // Signed min/max initialization // need extra QWORD bits for SSE2 FP conversion __m128 mMinValue128 = _mm_set1_ps( (float)( (QWORD)wMinValue ) ); __m128 mMaxValue128 = _mm_set1_ps( (float)( wMaxValue ) ); while( count >= DWordsPerPrefetch ) { Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Process cacheline values per pass count -= DWordsPerPrefetch; for( i = 0; i < DoubleQuadWordsPerPrefetch; i++ ) { // Get double-quadword values mValue128i = *(__m128i*)pBuffer; pBuffer += DWordsPerDoubleQuadWord; // Convert to FP mValue128 = _mm_cvtepi32_ps( mValue128i ); // Determine parallel min/max mMinValue128 = _mm_min_ps( mMinValue128, mValue128 ); mMaxValue128 = _mm_max_ps( mMaxValue128, mValue128 ); } } // Process double-quadword values per pass for remainder while( count >= DWordsPerDoubleQuadWord ) { // Process double-quadword values per pass count -= DWordsPerDoubleQuadWord; // Get double-quadword values mValue128i = *(__m128i*)pBuffer; pBuffer += DWordsPerDoubleQuadWord; // Convert to FP mValue128 = _mm_cvtepi32_ps( mValue128i ); // Determine parallel min/max mMinValue128 = _mm_min_ps( mMinValue128, mValue128 ); mMaxValue128 = _mm_max_ps( mMaxValue128, mValue128 ); } // Determine wMinValue // Convert back to DWORD __m128i mMinValue128i = _mm_cvtps_epi32( mMinValue128 ); // Extract each value in double-quadword to find minimum // Grab element 0 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( mMinValue128i ); wMinValue = Min( wMinValue, wValue ); // Grab element 1 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 4 ) ); wMinValue = Min( wMinValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 8 ) ); wMinValue = Min( wMinValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 12 ) ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Convert back to DWORD __m128i mMaxValue128i = _mm_cvtps_epi32( mMaxValue128 ); // Extract each value in double-quadword to find maximum // Grab element 0 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( mMaxValue128i ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 1 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 4 ) ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 8 ) ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 3 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 12 ) ); wMaxValue = Max( wMaxValue, wValue ); } // if( count >= DWordsPerDoubleQuadWord ) } // if( count >= DWordsPerDoubleQuadWord ) } // Find min/max per value while( count > 0 ) { count -= 1; wValue = *pBuffer++; wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } min = wMinValue; max = wMaxValue; } /*****************************************************************************\ Inline Function: FindDWordBufferMinMaxRestart Description: Finds the min and max unsigned 32-bit values in the buffer Excludes a restart value from min or max values Input: DWORD* pBuffer - pointer to 32-bit buffer const DWORD bytes - size of buffer in bytes const DWORD restart - restart index to ignore cpuInstructionLevel - indicates if SSE_4.1 is available Output: DWORD &min - minimum 32-bit value DWORD &max - maximum 32-bit value \*****************************************************************************/ inline void FindDWordBufferMinMaxRestart( DWORD* pBuffer, const DWORD bytes, const DWORD restart, DWORD &min, DWORD &max, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ) { // PrefetchBuffer( (BYTE*)pBuffer, bytes ); DWORD wValue = 0; DWORD wMinValue = 0xffffffff; DWORD wMaxValue = 0x00000000; DWORD count = bytes / sizeof(DWORD); #ifdef USE_SSE4_1 DWORD i = 0; if( IsAligned( pBuffer, sizeof(DWORD) ) && cpuInstructionLevel >= CPU_INSTRUCTION_LEVEL_SSE4_1 ) { const DWORD DoubleQuadWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DQWORD); const DWORD DWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DWORD); const DWORD DWordsPerDoubleQuadWord = sizeof(DQWORD) / sizeof(DWORD); Prefetch( (BYTE*)pBuffer + sizeof(PREFETCH) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Find min/max per cacheline of values if( count >= DWordsPerDoubleQuadWord ) { const DWORD doubleQuadwordAlignWords = GetAlignmentOffset( pBuffer, sizeof(DQWORD) ) / sizeof(DWORD); // If pBuffer is not double-quadword aligned then process // until aligned if( doubleQuadwordAlignWords ) { for( i = 0; i < doubleQuadwordAlignWords; i++ ) { wValue = *pBuffer++; if (wValue == restart) { continue; } wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } count -= doubleQuadwordAlignWords; } // Find min/max per cacheline of values if( count >= DWordsPerPrefetch ) { __m128i mInput, mRestarts, mMask; __m128i mAll_ones; __m128i mMinValue128i, mMaxValue128i; // This is just used for andnot mInput mAll_ones.m128i_u64[0] = 0xFFFFFFFFFFFFFFFF; mAll_ones.m128i_u64[1] = 0xFFFFFFFFFFFFFFFF; // start with really high min and really low max // What should happen if all values are restart? mMinValue128i.m128i_u64[0] = 0xFFFFFFFFFFFFFFFF; mMinValue128i.m128i_u64[1] = 0xFFFFFFFFFFFFFFFF; mMaxValue128i.m128i_u64[0] = 0x0000000000000000; mMaxValue128i.m128i_u64[1] = 0x0000000000000000; // Initialize register used for testing for restart index. mRestarts.m128i_u64[0] = mRestarts.m128i_u64[1] = (((UINT64) restart) << 32) | ((UINT64) restart); while( count >= DWordsPerPrefetch ) { Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Process cacheline values per pass count -= DWordsPerPrefetch; for( i = 0; i < DoubleQuadWordsPerPrefetch; i++ ) { // Get double-quadword values mInput = *(__m128i*)pBuffer; pBuffer += DWordsPerDoubleQuadWord; // Make mask of non-restart_index fields mMask = _mm_andnot_si128(_mm_cmpeq_epi32(mInput, mRestarts), mAll_ones); // Copy minimum and maximum fields for non-restarts mMinValue128i = _mm_blendv_epi8(mMinValue128i, _mm_min_epu32(mMinValue128i, mInput), mMask ); mMaxValue128i = _mm_blendv_epi8(mMaxValue128i, _mm_max_epu32(mMaxValue128i, mInput), mMask ); } } // Process double-quadword values per pass for remainder while( count >= DWordsPerDoubleQuadWord ) { // Process double-quadword values per pass count -= DWordsPerDoubleQuadWord; // Get double-quadword values mInput = *(__m128i*)pBuffer; pBuffer += DWordsPerDoubleQuadWord; // Make mask of non-restart_index fields mMask = _mm_andnot_si128(_mm_cmpeq_epi32(mInput, mRestarts), mAll_ones); // Copy minimum and maximum fields for non-restarts mMinValue128i = _mm_blendv_epi8(mMinValue128i, _mm_min_epu32(mMinValue128i, mInput), mMask ); mMaxValue128i = _mm_blendv_epi8(mMaxValue128i, _mm_max_epu32(mMaxValue128i, mInput), mMask ); } // Determine wMinValue // Extract each value in double-quadword to find minimum // Grab element 0 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( mMinValue128i ); wMinValue = Min( wMinValue, wValue ); // Grab element 1 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 4 ) ); wMinValue = Min( wMinValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 8 ) ); wMinValue = Min( wMinValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 12 ) ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Extract each value in double-quadword to find maximum // Grab element 0 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( mMaxValue128i ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 1 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 4 ) ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 8 ) ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 3 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 12 ) ); wMaxValue = Max( wMaxValue, wValue ); } // if( count >= DWordsPerPrefetch ) } // if( count >= DWordsPerDoubleQuadWord ) } #endif // USE_SSE4_1 // Find min/max per value while( count > 0 ) { count -= 1; wValue = *pBuffer++; if (wValue == restart) { continue; } wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } min = wMinValue; max = wMaxValue; } /*****************************************************************************\ Inline Function: FindWordBufferMinMaxCopy Description: Finds the min and max unsigned 16-bit values in the buffer Copies data from pBuffer to pDest at the same time Input: WORD* pDest - pointer to 16-bit buffer to copy into WORD* pBuffer - pointer to 16-bit index buffer const DWORD bytes - size of buffer in bytes Output: WORD &min - minimum 16-bit value WORD &max - maximum 16-bit value \*****************************************************************************/ inline void FindWordBufferMinMaxCopy( WORD* pDest, WORD* pBuffer, const DWORD bytes, WORD &min, WORD &max ) { // PrefetchBuffer( (BYTE*)pBuffer, bytes ); WORD wValue = 0; WORD wMinValue = 0xffff; WORD wMaxValue = 0x0000; size_t count = bytes / sizeof(WORD); size_t i = 0; if( IsAligned( pBuffer, sizeof(WORD) ) ) { const size_t DoubleQuadWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DQWORD); const size_t WordsPerPrefetch = sizeof(PREFETCH) / sizeof(WORD); const size_t WordsPerDoubleQuadWord = sizeof(DQWORD) / sizeof(WORD); Prefetch( (BYTE*)pBuffer + sizeof(PREFETCH) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Find min/max per cacheline of values if( count >= WordsPerDoubleQuadWord ) { const size_t doubleQuadwordAlignWords = GetAlignmentOffset( pBuffer, sizeof(DQWORD) ) / sizeof(WORD); // If pBuffer is not double-quadword aligned then process // until aligned if( doubleQuadwordAlignWords ) { for( i = 0; i < doubleQuadwordAlignWords; i++ ) { wValue = *pDest++ = *pBuffer++; wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } count -= doubleQuadwordAlignWords; } // Find min/max per cacheline of values if( count >= WordsPerDoubleQuadWord ) { __m128i mValue128i; // Need to convert unsigned values to signed values // since min/max is signed op __m128i mSignedScale128i = _mm_set1_epi16((WORD)0x8000); // Signed min/max initialization __m128i mMinValue128i = _mm_set1_epi16(wMinValue-(WORD)0x8000); __m128i mMaxValue128i = _mm_set1_epi16(wMaxValue-(WORD)0x8000); while( count >= WordsPerPrefetch ) { Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Process cacheline values per pass count -= WordsPerPrefetch; for( i = 0; i < DoubleQuadWordsPerPrefetch; i++ ) { // Get double-quadword values mValue128i = *(__m128i*)pBuffer; _mm_storeu_si128((__m128i*)pDest, mValue128i); pBuffer += WordsPerDoubleQuadWord; pDest += WordsPerDoubleQuadWord; // Make values signed mValue128i = _mm_sub_epi16( mValue128i, mSignedScale128i ); // Determine parallel min/max mMinValue128i = _mm_min_epi16( mMinValue128i, mValue128i ); mMaxValue128i = _mm_max_epi16( mMaxValue128i, mValue128i ); } } // Process double-quadword values per pass for remainder while( count >= WordsPerDoubleQuadWord ) { // Process double-quadword values per pass count -= WordsPerDoubleQuadWord; // Get double-quadword values mValue128i = *(__m128i*)pBuffer; _mm_storeu_si128((__m128i*)pDest, mValue128i); pBuffer += WordsPerDoubleQuadWord; pDest += WordsPerDoubleQuadWord; // Make values signed mValue128i = _mm_sub_epi16( mValue128i, mSignedScale128i ); // Determine parallel min/max mMinValue128i = _mm_min_epi16( mMinValue128i, mValue128i ); mMaxValue128i = _mm_max_epi16( mMaxValue128i, mValue128i ); } // Determine wMinValue // Make values unsigned mMinValue128i = _mm_add_epi16( mMinValue128i, mSignedScale128i ); // Extract each value in double-quadword to find minimum // for( i = 0; i < WordsPerDoubleQuadWord; i++ ) wValue = (WORD)_mm_extract_epi16( mMinValue128i, 0 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 1 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 2 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 3 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 4 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 5 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 6 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 7 ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Make values unsigned mMaxValue128i = _mm_add_epi16( mMaxValue128i, mSignedScale128i ); // Extract each value in double-quadword to find maximum // for( i = 0; i < WordsPerDoubleQuadWord; i++ ) wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 0 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 1 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 2 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 3 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 4 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 5 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 6 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 7 ); wMaxValue = Max( wMaxValue, wValue ); } // if( count >= WordsPerDoubleQuadWord ) } // if( count >= WordsPerDoubleQuadWord ) } #ifndef _WIN64 else // if( IsAligned( pBuffer, sizeof(WORD) ) ) { const size_t QuadWordsPerCacheline = sizeof(CACHELINE) / sizeof(QWORD); const size_t WordsPerCacheline = sizeof(CACHELINE) / sizeof(WORD); const size_t WordsPerQuadWord = sizeof(QWORD) / sizeof(WORD); Prefetch( (BYTE*)pBuffer + sizeof(CACHELINE) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(CACHELINE) ); if( count >= WordsPerQuadWord ) { __m64 mValue64; // Need to convert unsigned values to signed values // since min/max is signed op __m64 mSignedScale64 = _mm_set1_pi16((WORD)0x8000); // Signed min/max initialization __m64 mMinValue64 = _mm_set1_pi16(wMinValue-(WORD)0x8000); __m64 mMaxValue64 = _mm_set1_pi16(wMaxValue-(WORD)0x8000); // Find min/max per cacheline of values while( count >= WordsPerCacheline ) { Prefetch( (BYTE*)pBuffer + sizeof(CACHELINE) ); // Process cacheline values per pass count -= WordsPerCacheline; for( i = 0; i < QuadWordsPerCacheline; i++ ) { // Get quadword values mValue64 = *(__m64*)pBuffer; *(__m64*)pDest = mValue64; pBuffer += WordsPerQuadWord; pDest += WordsPerQuadWord; // Make values signed mValue64 = _mm_sub_pi16( mValue64, mSignedScale64 ); // Determine parallel min/max mMinValue64 = _mm_min_pi16( mMinValue64, mValue64 ); mMaxValue64 = _mm_max_pi16( mMaxValue64, mValue64 ); } } // Process quadword values per pass for remainder while( count >= WordsPerQuadWord ) { // Process quadword values per pass count -= WordsPerQuadWord; // Get quadword values mValue64 = *(__m64*)pBuffer; *(__m64*)pDest = mValue64; pBuffer += WordsPerQuadWord; pDest += WordsPerQuadWord; // Make values signed mValue64 = _mm_sub_pi16( mValue64, mSignedScale64 ); // Determine parallel min/max mMinValue64 = _mm_min_pi16( mMinValue64, mValue64 ); mMaxValue64 = _mm_max_pi16( mMaxValue64, mValue64 ); } // Determine wMinValue // Make values unsigned mMinValue64 = _mm_add_pi16( mMinValue64, mSignedScale64 ); // Extract each value in quadword to find minimum // for( i = 0; i < WordsPerQuadWord; i++ ) wValue = (WORD)_mm_extract_pi16( mMinValue64, 0 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMinValue64, 1 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMinValue64, 2 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMinValue64, 3 ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Make values unsigned mMaxValue64 = _mm_add_pi16( mMaxValue64, mSignedScale64 ); // Extract each value in quadword to find maximum // for( i = 0; i < WordsPerQuadWord; i++ ) wValue = (WORD)_mm_extract_pi16( mMaxValue64, 0 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMaxValue64, 1 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMaxValue64, 2 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_pi16( mMaxValue64, 3 ); wMaxValue = Max( wMaxValue, wValue ); _mm_empty(); } // if( count >= WordsPerQuadWord ) } #endif // Find min/max per value while( count > 0 ) { count -= 1; wValue = *pDest++ = *pBuffer++; wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } min = wMinValue; max = wMaxValue; } /*****************************************************************************\ Inline Function: FindDWordBufferMinMaxCopy Description: Finds the min and max unsigned 32-bit values in the buffer Copies data from pBuffer to pDest at the same time Input: DWORD* pDest - pointer to 32-bit buffer to copy into DWORD* pBuffer - pointer to 32-bit buffer const DWORD bytes - size of buffer in bytes Output: WORD &min - minimum 32-bit value WORD &max - maximum 32-bit value \*****************************************************************************/ inline void FindDWordBufferMinMaxCopy( DWORD* pDest, DWORD* pBuffer, const DWORD bytes, DWORD &min, DWORD &max ) { // PrefetchBuffer( (BYTE*)pBuffer, bytes ); DWORD wValue = 0; DWORD wMinValue = 0xffffffff; DWORD wMaxValue = 0x00000000; DWORD count = bytes / sizeof(DWORD); DWORD i = 0; if( IsAligned( pBuffer, sizeof(DWORD) ) ) { const DWORD DoubleQuadWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DQWORD); const DWORD DWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DWORD); const DWORD DWordsPerDoubleQuadWord = sizeof(DQWORD) / sizeof(DWORD); Prefetch( (BYTE*)pBuffer + sizeof(PREFETCH) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Find min/max per cacheline of values if( count >= DWordsPerDoubleQuadWord ) { const DWORD doubleQuadwordAlignWords = GetAlignmentOffset( pBuffer, sizeof(DQWORD) ) / sizeof(DWORD); // If pBuffer is not double-quadword aligned then process // until aligned if( doubleQuadwordAlignWords ) { for( i = 0; i < doubleQuadwordAlignWords; i++ ) { wValue = *pDest++ = *pBuffer++; wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } count -= doubleQuadwordAlignWords; } // Find min/max per cacheline of values if( count >= DWordsPerDoubleQuadWord ) { __m128i mValue128i; __m128 mValue128; // Signed min/max initialization // need extra QWORD bits for SSE2 FP conversion __m128 mMinValue128 = _mm_set1_ps( (float)( (QWORD)wMinValue ) ); __m128 mMaxValue128 = _mm_set1_ps( (float)( wMaxValue ) ); while( count >= DWordsPerPrefetch ) { Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Process cacheline values per pass count -= DWordsPerPrefetch; for( i = 0; i < DoubleQuadWordsPerPrefetch; i++ ) { // Get double-quadword values mValue128i = *(__m128i*)pBuffer; _mm_storeu_si128((__m128i*)pDest, mValue128i); pBuffer += DWordsPerDoubleQuadWord; pDest += DWordsPerDoubleQuadWord; // Convert to FP mValue128 = _mm_cvtepi32_ps( mValue128i ); // Determine parallel min/max mMinValue128 = _mm_min_ps( mMinValue128, mValue128 ); mMaxValue128 = _mm_max_ps( mMaxValue128, mValue128 ); } } // Process double-quadword values per pass for remainder while( count >= DWordsPerDoubleQuadWord ) { // Process double-quadword values per pass count -= DWordsPerDoubleQuadWord; // Get double-quadword values mValue128i = *(__m128i*)pBuffer; _mm_storeu_si128((__m128i*)pDest, mValue128i); pBuffer += DWordsPerDoubleQuadWord; pDest += DWordsPerDoubleQuadWord; // Convert to FP mValue128 = _mm_cvtepi32_ps( mValue128i ); // Determine parallel min/max mMinValue128 = _mm_min_ps( mMinValue128, mValue128 ); mMaxValue128 = _mm_max_ps( mMaxValue128, mValue128 ); } // Determine wMinValue // Convert back to DWORD __m128i mMinValue128i = _mm_cvtps_epi32( mMinValue128 ); // Extract each value in double-quadword to find minimum // Grab element 0 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( mMinValue128i ); wMinValue = Min( wMinValue, wValue ); // Grab element 1 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 4 ) ); wMinValue = Min( wMinValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 8 ) ); wMinValue = Min( wMinValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 12 ) ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Convert back to DWORD __m128i mMaxValue128i = _mm_cvtps_epi32( mMaxValue128 ); // Extract each value in double-quadword to find maximum // Grab element 0 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( mMaxValue128i ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 1 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 4 ) ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 8 ) ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 3 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 12 ) ); wMaxValue = Max( wMaxValue, wValue ); } // if( count >= DWordsPerDoubleQuadWord ) } // if( count >= DWordsPerDoubleQuadWord ) } // Find min/max per value while( count > 0 ) { count -= 1; wValue = *pDest++ = *pBuffer++; wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } min = wMinValue; max = wMaxValue; } /*****************************************************************************\ Inline Function: FindWordBufferMinMaxRestartCoy Description: Finds the min and max unsigned 32-bit values in the buffer Excludes a restart value from min or max values Copies data from pBuffer to pDest at the same time Input: WORD* pDest - pointer to 32-bit buffer to copy into WORD* pBuffer - pointer to 32-bit buffer const DWORD bytes - size of buffer in bytes const WORD restart - restart index to ignore cpuInstructionLevel - indicates if SSE_4.1 is available Output: WORD &min - minimum 32-bit value WORD &max - maximum 32-bit value \*****************************************************************************/ inline void FindWordBufferMinMaxRestartCopy( WORD* pDest, WORD* pBuffer, const DWORD bytes, const WORD restart, WORD &min, WORD &max, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ) { // PrefetchBuffer( (BYTE*)pBuffer, bytes ); WORD wValue = 0; WORD wMinValue = 0xffff; WORD wMaxValue = 0x0000; size_t count = bytes / sizeof(WORD); #ifdef USE_SSE4_1 size_t i = 0; if( IsAligned( pBuffer, sizeof(WORD) ) && cpuInstructionLevel >= CPU_INSTRUCTION_LEVEL_SSE4_1 ) { const DWORD DoubleQuadWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DQWORD); const DWORD WordsPerPrefetch = sizeof(PREFETCH) / sizeof(WORD); const DWORD WordsPerDoubleQuadWord = sizeof(DQWORD) / sizeof(WORD); Prefetch( (BYTE*)pBuffer + sizeof(PREFETCH) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Find min/max per cacheline of values if( count >= WordsPerDoubleQuadWord ) { const size_t doubleQuadwordAlignWords = GetAlignmentOffset( pBuffer, sizeof(DQWORD) ) / sizeof(WORD); // If pBuffer is not double-quadword aligned then process // until aligned if( doubleQuadwordAlignWords ) { for( i = 0; i < doubleQuadwordAlignWords; i++ ) { wValue = *pDest++ = *pBuffer++; if (wValue == restart) { continue; } wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } count -= doubleQuadwordAlignWords; } // Find min/max per cacheline of values if( count >= WordsPerDoubleQuadWord ) { __m128i mInput, mRestarts, mMask; __m128i mAll_ones; __m128i mMinValue128i, mMaxValue128i; // This is just used for andnot mInput mAll_ones.m128i_u64[0] = 0xFFFFFFFFFFFFFFFF; mAll_ones.m128i_u64[1] = 0xFFFFFFFFFFFFFFFF; // start with really high min and really low max // What should happen if all values are restart? mMinValue128i.m128i_u64[0] = 0xFFFFFFFFFFFFFFFF; mMinValue128i.m128i_u64[1] = 0xFFFFFFFFFFFFFFFF; mMaxValue128i.m128i_u64[0] = 0x0000000000000000; mMaxValue128i.m128i_u64[1] = 0x0000000000000000; // Initialize register used for testing for restart index. mRestarts.m128i_u64[0] = mRestarts.m128i_u64[1] = (((UINT64) restart) << 48) | (((UINT64) restart) << 32) | (((UINT64) restart) << 16) | ((UINT64) restart); while( count >= WordsPerPrefetch ) { Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Process cacheline values per pass count -= WordsPerPrefetch; for( i = 0; i < DoubleQuadWordsPerPrefetch; i++ ) { // Get double-quadword values mInput = *(__m128i*)pBuffer; _mm_storeu_si128((__m128i*)pDest, mInput); pBuffer += WordsPerDoubleQuadWord; pDest += WordsPerDoubleQuadWord; // Make mask of non-restart_index fields mMask = _mm_andnot_si128(_mm_cmpeq_epi16(mInput, mRestarts), mAll_ones); // Copy minimum and maximum fields for non-restarts mMinValue128i = _mm_blendv_epi8(mMinValue128i, _mm_min_epu16(mMinValue128i, mInput), mMask ); mMaxValue128i = _mm_blendv_epi8(mMaxValue128i, _mm_max_epu16(mMaxValue128i, mInput), mMask ); } } // Process double-quadword values per pass for remainder while( count >= WordsPerDoubleQuadWord ) { // Process double-quadword values per pass count -= WordsPerDoubleQuadWord; // Get double-quadword values mInput = *(__m128i*)pBuffer; _mm_storeu_si128((__m128i*)pDest, mInput); pBuffer += WordsPerDoubleQuadWord; pDest += WordsPerDoubleQuadWord; // Make mask of non-restart_index fields mMask = _mm_andnot_si128(_mm_cmpeq_epi16(mInput, mRestarts), mAll_ones); // Copy minimum and maximum fields for non-restarts mMinValue128i = _mm_blendv_epi8(mMinValue128i, _mm_min_epu16(mMinValue128i, mInput), mMask ); mMaxValue128i = _mm_blendv_epi8(mMaxValue128i, _mm_max_epu16(mMaxValue128i, mInput), mMask ); } // Determine wMinValue // Extract each value in double-quadword to find minimum // for( i = 0; i < WordsPerDoubleQuadWord; i++ ) wValue = (WORD)_mm_extract_epi16( mMinValue128i, 0 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 1 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 2 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 3 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 4 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 5 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 6 ); wMinValue = Min( wMinValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMinValue128i, 7 ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Extract each value in double-quadword to find maximum // for( i = 0; i < WordsPerDoubleQuadWord; i++ ) wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 0 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 1 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 2 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 3 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 4 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 5 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 6 ); wMaxValue = Max( wMaxValue, wValue ); wValue = (WORD)_mm_extract_epi16( mMaxValue128i, 7 ); wMaxValue = Max( wMaxValue, wValue ); } // if( count >= WordsPerDoubleQuadWord ) } // if( count >= WordsPerDoubleQuadWord ) } #endif // USE_SSE4_1 // Find min/max per value while( count > 0 ) { count -= 1; wValue = *pDest++ = *pBuffer++; if (wValue == restart) { continue; } wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } min = wMinValue; max = wMaxValue; } /*****************************************************************************\ Inline Function: FindDWordBufferMinMaxRestartCopy Description: Finds the min and max unsigned 32-bit values in the buffer Excludes a restart value from min or max values Copies data from pBuffer to pDest at the same time Input: DWORD* pDest - pointer to 32-bit buffer to copy into DWORD* pBuffer - pointer to 32-bit index buffer const DWORD bytes - size of buffer in bytes const DWORD restart - restart index to ignore cpuInstructionLevel - indicates if SSE_4.1 is available Output: DWORD &min - minimum 32-bit value DWORD &max - maximum 32-bit value \*****************************************************************************/ inline void FindDWordBufferMinMaxRestartCopy( DWORD* pDest, DWORD* pBuffer, const DWORD bytes, const DWORD restart, DWORD &min, DWORD &max, CPU_INSTRUCTION_LEVEL cpuInstructionLevel ) { // PrefetchBuffer( (BYTE*)pBuffer, bytes ); DWORD wValue = 0; DWORD wMinValue = 0xffffffff; DWORD wMaxValue = 0x00000000; DWORD count = bytes / sizeof(DWORD); #ifdef USE_SSE4_1 DWORD i = 0; if( IsAligned( pBuffer, sizeof(DWORD) ) && cpuInstructionLevel >= CPU_INSTRUCTION_LEVEL_SSE4_1 ) { const DWORD DoubleQuadWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DQWORD); const DWORD DWordsPerPrefetch = sizeof(PREFETCH) / sizeof(DWORD); const DWORD DWordsPerDoubleQuadWord = sizeof(DQWORD) / sizeof(DWORD); Prefetch( (BYTE*)pBuffer + sizeof(PREFETCH) ); Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Find min/max per cacheline of values if( count >= DWordsPerDoubleQuadWord ) { const DWORD doubleQuadwordAlignWords = GetAlignmentOffset( pBuffer, sizeof(DQWORD) ) / sizeof(DWORD); // If pBuffer is not double-quadword aligned then process // until aligned if( doubleQuadwordAlignWords ) { for( i = 0; i < doubleQuadwordAlignWords; i++ ) { wValue = *pDest++ = *pBuffer++; if (wValue == restart) { continue; } wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } count -= doubleQuadwordAlignWords; } // Find min/max per cacheline of values if( count >= DWordsPerPrefetch ) { __m128i mInput, mRestarts, mMask; __m128i mAll_ones; __m128i mMinValue128i, mMaxValue128i; // This is just used for andnot mInput mAll_ones.m128i_u64[0] = 0xFFFFFFFFFFFFFFFF; mAll_ones.m128i_u64[1] = 0xFFFFFFFFFFFFFFFF; // start with really high min and really low max // What should happen if all values are restart? mMinValue128i.m128i_u64[0] = 0xFFFFFFFFFFFFFFFF; mMinValue128i.m128i_u64[1] = 0xFFFFFFFFFFFFFFFF; mMaxValue128i.m128i_u64[0] = 0x0000000000000000; mMaxValue128i.m128i_u64[1] = 0x0000000000000000; // Initialize register used for testing for restart index. mRestarts.m128i_u64[0] = mRestarts.m128i_u64[1] = (((UINT64) restart) << 32) | ((UINT64) restart); while( count >= DWordsPerPrefetch ) { Prefetch( (BYTE*)pBuffer + 2 * sizeof(PREFETCH) ); // Process cacheline values per pass count -= DWordsPerPrefetch; for( i = 0; i < DoubleQuadWordsPerPrefetch; i++ ) { // Get double-quadword values mInput = *(__m128i*)pBuffer; _mm_storeu_si128((__m128i*)pDest, mInput); pBuffer += DWordsPerDoubleQuadWord; pDest += DWordsPerDoubleQuadWord; // Make mask of non-restart_index fields mMask = _mm_andnot_si128(_mm_cmpeq_epi32(mInput, mRestarts), mAll_ones); // Copy minimum and maximum fields for non-restarts mMinValue128i = _mm_blendv_epi8(mMinValue128i, _mm_min_epu32(mMinValue128i, mInput), mMask ); mMaxValue128i = _mm_blendv_epi8(mMaxValue128i, _mm_max_epu32(mMaxValue128i, mInput), mMask ); } } // Process double-quadword values per pass for remainder while( count >= DWordsPerDoubleQuadWord ) { // Process double-quadword values per pass count -= DWordsPerDoubleQuadWord; // Get double-quadword values mInput = *(__m128i*)pBuffer; _mm_storeu_si128((__m128i*)pDest, mInput); pBuffer += DWordsPerDoubleQuadWord; pDest += DWordsPerDoubleQuadWord; // Make mask of non-restart_index fields mMask = _mm_andnot_si128(_mm_cmpeq_epi32(mInput, mRestarts), mAll_ones); // Copy minimum and maximum fields for non-restarts mMinValue128i = _mm_blendv_epi8(mMinValue128i, _mm_min_epu32(mMinValue128i, mInput), mMask ); mMaxValue128i = _mm_blendv_epi8(mMaxValue128i, _mm_max_epu32(mMaxValue128i, mInput), mMask ); } // Determine wMinValue // Extract each value in double-quadword to find minimum // Grab element 0 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( mMinValue128i ); wMinValue = Min( wMinValue, wValue ); // Grab element 1 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 4 ) ); wMinValue = Min( wMinValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 8 ) ); wMinValue = Min( wMinValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMinValue128i, 12 ) ); wMinValue = Min( wMinValue, wValue ); // Determine wMaxValue // Extract each value in double-quadword to find maximum // Grab element 0 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( mMaxValue128i ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 1 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 4 ) ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 2 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 8 ) ); wMaxValue = Max( wMaxValue, wValue ); // Grab element 3 from m128i reg: 3 | 2 | 1 | 0 wValue = (DWORD)_mm_cvtsi128_si32( _mm_srli_si128( mMaxValue128i, 12 ) ); wMaxValue = Max( wMaxValue, wValue ); } // if( count >= DWordsPerPrefetch ) } // if( count >= DWordsPerDoubleQuadWord ) } #endif // USE_SSE4_1 // Find min/max per value while( count > 0 ) { count -= 1; wValue = *pDest++ = *pBuffer++; if (wValue == restart) { continue; } wMinValue = Min( wMinValue, wValue ); wMaxValue = Max( wMaxValue, wValue ); } min = wMinValue; max = wMaxValue; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Object.h000066400000000000000000000214461363533017100237530ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "types.h" #include "Alloc.h" #include #ifdef ISTDLIB_MT #include "Threading.h" #endif #if defined(MSVC) #define STD_API_CALL __stdcall #else #define STD_API_CALL #endif #define NO_VTABLE __declspec(novtable) namespace iSTD { /*****************************************************************************\ Class: CObject Description: Base class for all objects \*****************************************************************************/ template class NO_VTABLE CObject { public: long Acquire( void ); long Release( void ); long GetRefCount( void ) const; static long STD_API_CALL SafeAcquire(CObject* ptr); static long STD_API_CALL SafeRelease(CObject* ptr); void* operator new( size_t size ); void* operator new[]( size_t size ); void* operator new( size_t size, void* placement); void operator delete(void* ptr); void operator delete[]( void* ptr ); void operator delete(void* ptr, void* placement); protected: CObject( void ); virtual ~CObject(void); #ifdef ISTDLIB_MT volatile long m_RefCount; #else long m_RefCount; #endif }; /*****************************************************************************\ Function: CObject constructor Description: Initializes internal data Input: default Output: none \*****************************************************************************/ template inline CObject::CObject( void ) { #ifdef ISTDLIB_MT ASSERT( IsAligned( (void*)&m_RefCount, sizeof(DWORD) ) ); #endif m_RefCount = 0; } /*****************************************************************************\ Function: CObject destructor Description: Deletes internal data Input: default Output: none \*****************************************************************************/ template inline CObject::~CObject(void) { ASSERT( m_RefCount == 0 ); } /*****************************************************************************\ Function: CObject::Acquire Description: Increments and returns the current reference count Input: none Output: long - reference count \*****************************************************************************/ template inline long CObject::Acquire( void ) { ASSERT( m_RefCount >= 0 ); ASSERT( m_RefCount < LONG_MAX ); #if defined(ISTDLIB_MT) && defined(__linux__) __sync_fetch_and_add(&m_RefCount, 1); #elif defined(ISTDLIB_MT) ::InterlockedIncrement(&m_RefCount); #else ++m_RefCount; #endif return m_RefCount; } /*****************************************************************************\ Function: CObject::Release Description: Decrements the current reference count. Deletes the object when the reference count reaches zero. Returns the current reference count. Input: none Output: long - reference count \*****************************************************************************/ template inline long CObject::Release( void ) { ASSERT( m_RefCount > 0 ); #if defined(ISTDLIB_MT) && defined(__linux__) __sync_sub_and_fetch(&m_RefCount, 1); #elif defined(ISTDLIB_MT) ::InterlockedDecrement(&m_RefCount); #else --m_RefCount; #endif if( m_RefCount == 0 ) { delete this; return 0; } else { return m_RefCount; } } /*****************************************************************************\ Function: CObject::GetRefCount Description: Returns the current reference count. Input: none Output: long - reference count \*****************************************************************************/ template inline long CObject::GetRefCount( void ) const { return m_RefCount; } /*****************************************************************************\ Function: CObject::SafeAcquire Description: Static function that calls the object's acquire function if the object exists Input: CObject* ptr - pointer to object to acquire Output: long - reference count \*****************************************************************************/ template inline long CObject::SafeAcquire( CObject* ptr ) { if( ptr ) { return ptr->Acquire(); } else { return 0; } } /*****************************************************************************\ Function: CObject::SafeRelease Description: Static function that calls the object's release function if the object exists Input: CObject* ptr - pointer to object to release Output: long - reference count \*****************************************************************************/ template inline long CObject::SafeRelease( CObject* ptr ) { if( ptr ) { return ptr->Release(); } else { return 0; } } /*****************************************************************************\ operator new \*****************************************************************************/ template inline void* CObject::operator new( size_t size ) { ASSERT( size ); #ifdef ISTDLIB_MT void* ptr = CAllocatorType::AlignedAllocate( size, sizeof(DWORD) ); #else void* ptr = CAllocatorType::Allocate( size ); #endif ASSERT( ptr ); return ptr; } /*****************************************************************************\ operator new[] \*****************************************************************************/ template inline void* CObject::operator new[]( size_t size ) { ASSERT( size ); #ifdef ISTDLIB_MT void* ptr = CAllocatorType::AlignedAllocate( size, sizeof(DWORD) ); #else void* ptr = CAllocatorType::Allocate( size ); #endif ASSERT( ptr ); return ptr; } /*****************************************************************************\ operator new with placement \*****************************************************************************/ template inline void* CObject::operator new( size_t size, void* placement ) { ASSERT( size ); ASSERT( placement ); return placement; } /*****************************************************************************\ operator delete \*****************************************************************************/ template inline void CObject::operator delete(void* ptr) { ASSERT( ptr ); #ifdef ISTDLIB_MT CAllocatorType::AlignedDeallocate( ptr ); #else CAllocatorType::Deallocate( ptr ); #endif } /*****************************************************************************\ operator delete[] \*****************************************************************************/ template inline void CObject::operator delete[]( void* ptr ) { ASSERT( ptr ); #ifdef ISTDLIB_MT CAllocatorType::AlignedDeallocate( ptr ); #else CAllocatorType::Deallocate( ptr ); #endif } /*****************************************************************************\ operator delete from placement \*****************************************************************************/ template inline void CObject::operator delete( void* ptr, void* placement ) { ASSERT( ptr ); ASSERT( placement ); ASSERT( ptr == placement ); } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Pointer.h000066400000000000000000000077431363533017100241710ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once namespace iSTD { /*****************************************************************************\ Class: CPointer Description: \*****************************************************************************/ template class CPointer { public: CPointer( void ); virtual ~CPointer( void ); CPointer& operator= ( Type* rValue ); CPointer& operator= ( CPointer rValue ); Type& operator[] ( long index ); Type& operator* ( void ); Type* operator-> ( void ); protected: Type* m_Pointer; }; /*****************************************************************************\ Function: Description: Input: Output: \*****************************************************************************/ template CPointer::CPointer( void ) : Object() { m_Pointer = NULL; } /*****************************************************************************\ Function: Description: Input: Output: \*****************************************************************************/ template CPointer::~CPointer( void ) { m_Pointer = NULL; } /*****************************************************************************\ Function: Description: Input: Output: \*****************************************************************************/ template CPointer& CPointer::operator= ( Type* rValue ) { m_Pointer = rValue; return *this; } /*****************************************************************************\ Function: Description: Input: Output: \*****************************************************************************/ template CPointer& CPointer::operator= ( CPointer rValue ) { m_Pointer = rValue.m_Pointer; return *this; } /*****************************************************************************\ Function: Description: Input: Output: \*****************************************************************************/ template Type& CPointer::operator[] ( long index ) { // TODO: exception handling // TODO: bounds checking return m_Pointer[ index ]; } /*****************************************************************************\ Function: Description: Input: Output: \*****************************************************************************/ template Type& CPointer::operator* ( void ) { // TODO: exception handling return *m_Pointer; } /*****************************************************************************\ Function: Description: Input: Output: \*****************************************************************************/ template Type* CObjectPointer::operator-> ( void ) { return m_Pointer; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Print.h000066400000000000000000000055601363533017100236400ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #ifdef __cplusplus #ifdef _WIN32 #include #if defined ISTDLIB_KMD # include #endif #if defined ISTDLIB_UMD && !defined UNIT_TESTING # include # include #endif namespace iSTD { /*****************************************************************************\ Extern: EngDebugPrint Defined in winddi.h \*****************************************************************************/ #if defined(ISTDLIB_KMD) extern "C" void APIENTRY EngDebugPrint( PCHAR, PCHAR, va_list ); #endif /*****************************************************************************\ Inline Function: PrintMessage PURPOSE: Prints a message for both debug and release drivers \*****************************************************************************/ inline void __cdecl PrintMessage( char* str, ... ) { if( str ) { va_list args; va_start( args, str ); const size_t length = ::_vscprintf( str, args ) + 1; char* temp = new char[ length ]; if( temp ) { #if defined(ISTDLIB_KMD) // Send message to kernel debugger ::_vsnprintf( temp, length, str, args ); EngDebugPrint( "INTC: ", "%s", (PCHAR)&temp ); #elif defined(ISTDLIB_UMD) #ifndef UNIT_TESTING ::_vsnprintf_s( temp, length, length, str, args ); OutputDebugStringA( "INTC: " ); OutputDebugStringA( temp ); #endif #endif delete[] temp; } va_end( args ); } } } // namespace iSTD #endif // _WIN32 #endif // __cplusplus intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Queue.h000066400000000000000000000072531363533017100236310ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "LinkedList.h" namespace iSTD { /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define QueueTemplateList class Type, class CAllocatorType #define CQueueType CQueue /*****************************************************************************\ Class: CQueue Description: Implements an linked-list-based queue \*****************************************************************************/ template class CQueue : public CLinkedListType { public: bool Push( const Type element ); Type Pop( void ); Type Top( void ) const; }; /*****************************************************************************\ Function: CQueue::Push Description: Pushes an element on the queue Input: const Type element Output: bool - success or fail \*****************************************************************************/ template bool CQueueType::Push( const Type element ) { // Add element to the top of list return this->Add( element ); } /*****************************************************************************\ Function: CQueue::Pop Description: Pops an element off the queue Input: none Output: Type - element \*****************************************************************************/ template Type CQueueType::Pop( void ) { Type element = {0}; if( this->IsEmpty() ) { ASSERT(0); } else { // Get the last element on the list typename CQueue::CIterator end = this->End(); --end; element = *end; // Remove the last element this->Remove( end ); } return element; } /*****************************************************************************\ Function: CQueue::Top Description: Returns the top element of the queue Input: none Output: Type - element \*****************************************************************************/ template Type CQueueType::Top( void ) const { Type element = {0}; if( this->IsEmpty() ) { ASSERT(0); } else { // Get the last element on the list typename CQueueType::CConstIterator end = this->End(); --end; element = *end; } return element; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/SparseSet.h000066400000000000000000000545611363533017100244620ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Object.h" #include "MemCopy.h" namespace iSTD { /*****************************************************************************\ Template Parameters \*****************************************************************************/ #define SparseSetTemplateList class CAllocatorType #define CSparseSetType CSparseSet /*****************************************************************************\ Class: CSparseSet Description: \*****************************************************************************/ template class CSparseSet : public CObject { public: CSparseSet( void ); CSparseSet( DWORD size ); CSparseSet( const CSparseSetType& other ); virtual ~CSparseSet( void ); void Resize( DWORD size ); void Clear( void ); void SetAll( void ); void Invert( void ); bool IsEmpty() const; bool IsSet( DWORD index ) const; bool Intersects( const CSparseSetType& other ) const; void Set( DWORD index ); void Set( const CSparseSetType& other ); void UnSet( DWORD index ); void UnSet( const CSparseSetType& other ); bool UnsafeIsSet( DWORD index ) const; void UnsafeSet( DWORD index ); DWORD GetSize( void ) const; bool operator==( const CSparseSetType& other ) const; bool operator!=( const CSparseSetType& other ) const; CSparseSetType& operator= ( const CSparseSetType& other ); CSparseSetType& operator|= ( const CSparseSetType& other ); CSparseSetType& operator&= ( const CSparseSetType& other ); DWORD GetNumMembers( void ) const; DWORD GetMember( DWORD memberNum ) const; protected: DWORD* m_Array; DWORD* m_Members; DWORD m_Size; DWORD m_NumMembers; void Create( DWORD size ); void Copy( const CSparseSetType& other ); void Delete( void ); }; /*****************************************************************************\ Function: CSparseSet Constructor Description: Initializes the set. The set is initially empty. Input: Output: none \*****************************************************************************/ template CSparseSetType::CSparseSet( void ) : CObject() { m_Array = 0; m_Members = 0; m_Size = 0; m_NumMembers = 0; } /*****************************************************************************\ Function: CSparseSet Constructor Description: Initializes the set. The set is initially empty. Input: DWORD size - initial size of the set Output: none \*****************************************************************************/ template CSparseSetType::CSparseSet( DWORD size ) : CObject() { m_Array = 0; m_Members = 0; m_Size = 0; m_NumMembers = 0; Create( size ); } /*****************************************************************************\ Function: CSparseSet Copy Constructor Description: Initializes the set. Input: const CSparseSetType& other - other set to copy Output: none \*****************************************************************************/ template CSparseSetType::CSparseSet( const CSparseSetType& other ) : CObject() { m_Array = 0; m_Members = 0; m_Size = 0; m_NumMembers = 0; Copy( other ); } /*****************************************************************************\ Function: CSparseSet Destructor Description: Frees all internal dynamic memory Input: none Output: none \*****************************************************************************/ template CSparseSetType::~CSparseSet( void ) { Delete(); } /*****************************************************************************\ Function: CSparseSet::Resize Description: Resizes the set. Note that this is a destructive operation, i.e. the set contents are not preserved on a resize. This behavior is different than the behavior for BitSets. Input: DWORD size - new size of the set Output: none \*****************************************************************************/ template void CSparseSetType::Resize( DWORD size ) { Create( size ); } /*****************************************************************************\ Function: CSparseSet::Clear Description: Unsets all bits in the sparse set Input: none Output: none \*****************************************************************************/ template void CSparseSetType::Clear( void ) { m_NumMembers = 0; } /*****************************************************************************\ Function: CSparseSet::SetAll Description: Sets all the bits in this sparse set. This is not a particularly fast operation. Input: void Output: void \*****************************************************************************/ template void CSparseSetType::SetAll( void ) { DWORD index = 0; for( index = 0; index < GetSize(); index++ ) { Set( index ); } } /*****************************************************************************\ Function: CSparseSet::Invert Description: Computes the inverse of this sparse set. This is not a particularly fast operation either. Input: void Output: void \*****************************************************************************/ template void CSparseSetType::Invert( void ) { DWORD index = 0; for( index = 0; index < GetSize(); index++ ) { if( IsSet( index ) ) { UnSet( index ); } else { Set( index ); } } } /*****************************************************************************\ Function: CSparseSet::IsEmpty Description: Determines if any bits are on in the bit set. Input: none Output: bool \*****************************************************************************/ template bool CSparseSetType::IsEmpty( void ) const { if( GetNumMembers() == 0 ) { return true; } return false; } /*****************************************************************************\ Function: CSparseSet::IsSet Description: Returns true if the specified index exists in the set, false otherwise. Input: DWORD index - index to check Output: bool \*****************************************************************************/ template bool CSparseSetType::IsSet( DWORD index ) const { bool isSet = false; if( index < GetSize() ) { DWORD memberNum = m_Array[ index ]; if( memberNum < GetNumMembers() ) { DWORD member = GetMember( memberNum ); isSet = ( member == index ); } } return isSet; } /*****************************************************************************\ Function: CSparseSet::UnsafeIsSet Description: Returns true if the specified index exists in the set, false otherwise. Note that function does not check if index is in range! Input: DWORD index - index to check Output: bool \*****************************************************************************/ template bool CSparseSetType::UnsafeIsSet( DWORD index ) const { bool isSet = false; DWORD memberNum = m_Array[ index ]; if( memberNum < GetNumMembers() ) { DWORD member = GetMember( memberNum ); isSet = ( member == index ); } return isSet; } /*****************************************************************************\ Function: CSparseSet::Intersects Description: Returns true if any members exist in both this set and the passed-in set. This is a shortcut for ( Set1 & Set2 ).IsEmpty(). Input: const CSparseSetType& other - Other set Output: bool \*****************************************************************************/ template bool CSparseSetType::Intersects( const CSparseSetType& other ) const { const CSparseSetType* smallSet = &other; const CSparseSetType* bigSet = this; if( smallSet->GetNumMembers() > bigSet->GetNumMembers() ) { const CSparseSetType *tmp = smallSet; smallSet = bigSet; bigSet = tmp; } DWORD memberNum = smallSet->GetNumMembers(); DWORD index = 0; while( memberNum-- ) { index = smallSet->GetMember( memberNum ); if( bigSet->IsSet( index ) ) { return true; } } return false; } /*****************************************************************************\ Function: CSparseSet::Set Description: Sets the bit at the given index. Input: DWORD index - index of the bit to set Output: void \*****************************************************************************/ template void CSparseSetType::Set( DWORD index ) { // If the index is larger than the size of this set then grow the set. if( index >= GetSize() ) { Create( index + 1 ); } if( index < GetSize() ) { if( IsSet( index ) == false ) { m_Array[ index ] = m_NumMembers; m_Members[ m_NumMembers ] = index; m_NumMembers++; } } else { ASSERT(0); } ASSERT( IsSet( index ) ); } /*****************************************************************************\ Function: CSparseSet::UnsafeSet Description: Sets the bit at the given index. Note that function does not check if index is in range! Input: DWORD index - index of the bit to set Output: void \*****************************************************************************/ template void CSparseSetType::UnsafeSet( DWORD index ) { ASSERT( index < GetSize() ); if( UnsafeIsSet( index ) == false ) { m_Array[ index ] = m_NumMembers; m_Members[ m_NumMembers ] = index; m_NumMembers++; } ASSERT( IsSet( index) ); } /*****************************************************************************\ Function: CSparseSet::Set Description: Sets all of the given bits. Input: CSparseSetType other - bits to set. Output: void \*****************************************************************************/ template void CSparseSetType::Set( const CSparseSetType& other ) { DWORD memberNum = other.GetNumMembers(); DWORD index = 0; while( memberNum-- ) { index = other.GetMember( memberNum ); Set( index ); } } /*****************************************************************************\ Function: CSparseSet::UnSet Description: Un-Sets the bit at the given index. Input: DWORD index - index of the bit to un-set Output: void \*****************************************************************************/ template void CSparseSetType::UnSet( DWORD index ) { // If the index is larger than the size of this set then grow the set. if( index >= GetSize() ) { Create( index + 1 ); } if( index < GetSize() ) { if( IsSet( index ) ) { m_NumMembers--; DWORD movedIndex = m_Members[ m_NumMembers ]; DWORD movedMember = m_Array[ index ]; m_Array[ movedIndex ] = movedMember; m_Members[ movedMember ] = movedIndex; } } else { ASSERT(0); } ASSERT( IsSet( index) == false ); } /*****************************************************************************\ Function: CSparseSet::UnSet Description: Un-Sets all of the given bits. Input: CSparseSetType other - bits to un-set. Output: void \*****************************************************************************/ template void CSparseSetType::UnSet( const CSparseSetType& other ) { DWORD memberNum = other.GetNumMembers(); DWORD index = 0; while( memberNum-- ) { index = other.GetMember( memberNum ); UnSet( index ); } } /*****************************************************************************\ Function: CSparseSet::GetSize Description: Returns the maximum number of elements in the sparse set. Input: void Output: DWORD length \*****************************************************************************/ template DWORD CSparseSetType::GetSize( void ) const { return m_Size; } /*****************************************************************************\ Function: CSparseSet::operator == Description: Tests this sparse set and another sparse set for equality. Input: CSparseSetType& other - other sparse set Output: bool \*****************************************************************************/ template bool CSparseSetType::operator==( const CSparseSetType& other ) const { if( ( GetSize() == other.GetSize() ) && ( GetNumMembers() == other.GetNumMembers() ) ) { DWORD memberNum = other.GetNumMembers(); DWORD index = 0; while( memberNum-- ) { index = other.GetMember( memberNum ); if( IsSet( index ) == false ) { return false; } } return true; } return false; } /*****************************************************************************\ Function: CSparseSet::operator != Description: Tests this sparse set and another sparse set for inequality. Input: CSparseSetType& other - other sparse set Output: bool \*****************************************************************************/ template bool CSparseSetType::operator!=( const CSparseSetType& other ) const { if( ( GetSize() == other.GetSize() ) && ( GetNumMembers() == other.GetNumMembers() ) ) { DWORD memberNum = other.GetNumMembers(); DWORD index = 0; while( memberNum-- ) { index = other.GetMember( memberNum ); if( IsSet( index ) == false ) { return true; } } return false; } return true; } /*****************************************************************************\ Function: CSparseSet::operator = Description: Equal operator to copy a sparse set. Input: CSparseSetType& other - sparse set to copy Output: *this \*****************************************************************************/ template CSparseSetType& CSparseSetType::operator= ( const CSparseSetType &other ) { Copy( other ); return *this; } /*****************************************************************************\ Function: CSparseSet::operator |= Description: Computes the union of this sparse set with another sparse set. Input: CSparseSetType& other - other sparse set Output: *this \*****************************************************************************/ template CSparseSetType& CSparseSetType::operator|= ( const CSparseSetType &other ) { DWORD memberNum = other.GetNumMembers(); DWORD index = 0; while( memberNum-- ) { index = other.GetMember( memberNum ); Set( index ); } return *this; } /*****************************************************************************\ Function: CSparseSet::operator &= Description: Computes the intersection of this sparse set with another sparse set. Input: CSparseSetType& other - other sparse set Output: *this \*****************************************************************************/ template CSparseSetType& CSparseSetType::operator&= ( const CSparseSetType &other ) { DWORD memberNum = GetNumMembers(); DWORD index = 0; while( memberNum-- ) { index = GetMember( memberNum ); if( other.IsSet( index ) == false ) { UnSet( index ); } } return *this; } /*****************************************************************************\ Function: CSparseSet::GetNumMembers Description: Returns the number of members in this sparse set. Input: void Output: DWORD number of members in this sparse set \*****************************************************************************/ template DWORD CSparseSetType::GetNumMembers( void ) const { return m_NumMembers; } /*****************************************************************************\ Function: CSparseSet::GetMember Description: Returns a member of this sparse set, given a member number. Input: void Output: DWORD member of this sparse set \*****************************************************************************/ template DWORD CSparseSetType::GetMember( DWORD memberNum ) const { ASSERT( memberNum < GetNumMembers() ); return m_Members[ memberNum ]; } /*****************************************************************************\ Function: CSparseSet::Create Description: Creates the internal sparse set structure of the specified size Input: DWORD size - number of elements Output: void \*****************************************************************************/ template void CSparseSetType::Create( DWORD size ) { const DWORD newArraySize = size; const DWORD oldArraySize = GetSize(); if( newArraySize == oldArraySize ) { // Nothing to do. } else if( newArraySize ) { DWORD* newArray = (DWORD*)CAllocatorType::Allocate( sizeof(DWORD) * newArraySize ); DWORD* newMembers = (DWORD*)CAllocatorType::Allocate( sizeof(DWORD) * newArraySize ); if( newArray && newMembers ) { if( m_Array && ( newArraySize > oldArraySize ) ) { MemCopy( newArray, m_Array, oldArraySize * sizeof(DWORD) ); SafeMemSet( newArray + oldArraySize, 0, ( newArraySize - oldArraySize) * sizeof(DWORD) ); } else { SafeMemSet( newArray, 0, newArraySize * sizeof(DWORD) ); } if( m_Members && ( newArraySize > oldArraySize ) ) { MemCopy( newMembers, m_Members, oldArraySize * sizeof(DWORD) ); SafeMemSet( newMembers + oldArraySize, 0, ( newArraySize - oldArraySize) * sizeof(DWORD) ); } else { SafeMemSet( newMembers, 0, newArraySize * sizeof(DWORD) ); } Delete(); m_Array = newArray; m_Members = newMembers; m_Size = size; } else { CAllocatorType::Deallocate( newArray ); newArray = 0; CAllocatorType::Deallocate( newMembers ); newMembers = 0; } } else { Delete(); } } /*****************************************************************************\ Function: CSparseSet::Copy Description: Copies information from one sparse set to this sparse set. Input: void Output: void \*****************************************************************************/ template void CSparseSetType::Copy( const CSparseSetType& other ) { if( GetSize() == other.GetSize() ) { if( this != &other ) { MemCopy( m_Array, other.m_Array, GetSize() * sizeof(DWORD) ); MemCopy( m_Members, other.m_Members, GetSize() * sizeof(DWORD) ); m_NumMembers = other.GetNumMembers(); } else { // Nothing to do. } } else { Create( other.GetSize() ); if( GetSize() == other.GetSize() ) { MemCopy( m_Array, other.m_Array, GetSize() * sizeof(DWORD) ); MemCopy( m_Members, other.m_Members, GetSize() * sizeof(DWORD) ); m_NumMembers = other.GetNumMembers(); } else { ASSERT( 0 ); } } } /*****************************************************************************\ Function: CSparseSet::Delete Description: Deletes the internal sparse set structure Input: void Output: void \*****************************************************************************/ template void CSparseSetType::Delete( void ) { CAllocatorType::Deallocate( m_Array ); m_Array = 0; CAllocatorType::Deallocate( m_Members ); m_Members = 0; m_Size = 0; m_NumMembers = 0; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Stack.h000066400000000000000000000452421363533017100236120ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Macros.h" #include "Object.h" #include "utility.h" #include "Threading.h" namespace iSTD { // Macro used for calculation of next stack node (undefined at the bottom of file). // Rounding to the higher number is used. #define CALCULATE_NEXT_NODE_SIZE( prevSize, growthFactor ) \ ((prevSize * growthFactor + 99) / 100) /*****************************************************************************\ Template Parameters: ElemType - type of stored element. CAllocatorType - allocator used for stack node allocations. BaseSize - Size of statically allocated buffer. Base for further growth. GrowthFactor - Defines the size of the next allocated stack node. E.g. if 100, size will not change, if 200 next node will be twice as large as the previous one. \*****************************************************************************/ #define StackTemplateList \ class ElemType, class CAllocatorType, DWORD BaseSize, DWORD GrowthFactor #define StackDeclTemplateList \ class ElemType, class CAllocatorType, DWORD BaseSize = 4, DWORD GrowthFactor = 135 #define CStackType \ CStack< ElemType, CAllocatorType, BaseSize, GrowthFactor > /*****************************************************************************\ Class: CStack Description: Stack class that can be optimized for number of dynamic allocations. It also supports storing limited number of elements (define with BaseSize template parameter) without any heap allocations. \*****************************************************************************/ template class CStack : public CObject { ISTD_DISALLOW_COPY_AND_ASSIGN( CStack ); // Make sure we won't get size 0: C_ASSERT( CALCULATE_NEXT_NODE_SIZE(BaseSize, GrowthFactor) > 0 ); public: CStack(); ~CStack(); DWORD GetCount( void ) const; bool IsEmpty( void ) const; bool Push(ElemType element); ElemType Pop( void ); ElemType Top( void ) const; bool Contains( const ElemType& elem ) const; protected: /*************************************************************************\ Class: CStackNode Description: Nodes are used to store elements on the heap. Nodes are linked with LIFO queue with pointer the the parent (node under current). \*************************************************************************/ class CStackNode : CObject { ISTD_DISALLOW_COPY_AND_ASSIGN( CStackNode ); public: static bool Create( DWORD size, CStackNode*& pNewNode ); static bool Create( DWORD size, CStackNode* pParentNode, CStackNode*& pNewNode ); static void Delete( CStackNode*& pNode ); bool IsEmpty( void ) const; bool IsFull( void ) const; DWORD GetMaxSize( void ) const; CStackNode* GetParentNode( void ) const; void Push(ElemType element); ElemType Pop( void ); ElemType Top( void ) const; bool Contains( const ElemType& elem ) const; private: CStackNode( DWORD size ); CStackNode( DWORD size, CStackNode* pParentNode ); ~CStackNode(); bool Initialize( void ); const DWORD m_cMaxSize; DWORD m_Count; ElemType* m_pElements; CStackNode* m_pParentNode; }; // Size of statically allocated buffer: static const DWORD m_cStaticSize = BaseSize; // Current number of elements: DWORD m_Count; // Top stack node. Null if all elements fits in m_StaticArray. CStackNode* m_pTopNode; // Static buffer for limited number of elements: ElemType m_StaticArray[m_cStaticSize]; DECL_DEBUG_MUTEX( m_InstanceNotThreadSafe ) }; /*****************************************************************************\ Function: CStack constructor. \*****************************************************************************/ template CStackType::CStack() : m_Count( 0 ), m_pTopNode( NULL ) { INIT_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CStack destructor. \*****************************************************************************/ template CStackType::~CStack() { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); // Free stack nodes if there are any: while( m_pTopNode ) { CStackNode* pParent = m_pTopNode->GetParentNode(); CStackNode::Delete( m_pTopNode ); m_pTopNode = pParent; } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); DELETE_DEBUG_MUTEX( m_InstanceNotThreadSafe ); } /*****************************************************************************\ Function: CStack::GetCount Description: Get current number of elements on the stack. Input: Output: DWORD \*****************************************************************************/ template DWORD CStackType::GetCount( void ) const { return m_Count; } /*****************************************************************************\ Function: CStack::Push Description: Push element on the stack. Input: ElemType element Output: bool - false for allocation failure \*****************************************************************************/ template bool CStackType::Push( ElemType element ) { ACQUIRE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); bool success = true; if( m_Count < m_cStaticSize ) { // Add to static array: m_StaticArray[m_Count++] = element; } else { // Element doesn't fit in static array. if( m_pTopNode == NULL ) { // Allocate first stack node: const DWORD newSize = CALCULATE_NEXT_NODE_SIZE( m_cStaticSize, GrowthFactor ); success = CStackNode::Create( newSize, m_pTopNode ); } else if( m_pTopNode->IsFull() ) { // Top stack node full - allocate another: const DWORD newSize = CALCULATE_NEXT_NODE_SIZE( m_pTopNode->GetMaxSize(), GrowthFactor ); success = CStackNode::Create( newSize, m_pTopNode, m_pTopNode ); } if( success ) { ++m_Count; m_pTopNode->Push( element ); } } RELEASE_DEBUG_MUTEX_WRITE( m_InstanceNotThreadSafe ); return success; } /*****************************************************************************\ Function: CStack::Pop Description: Pop element from the stack. Input: Output: ElemType - Top element. \*****************************************************************************/ template ElemType CStackType::Pop( void ) { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); ASSERT( !IsEmpty() ); ElemType elem; if( m_Count <= m_cStaticSize ) { // Element from static array. elem = m_StaticArray[--m_Count]; } else { // Element from stack node. if( m_pTopNode->IsEmpty() ) { // Top node empty - proceed to next one. CStackNode* pParentNode = m_pTopNode->GetParentNode(); CStackNode::Delete( m_pTopNode ); m_pTopNode = pParentNode; ASSERT( m_pTopNode ); } --m_Count; elem = m_pTopNode->Pop(); } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return elem; } /*****************************************************************************\ Function: CStack::Top Description: Get the top element without popping it from the stack. Input: Output: ElemType - Top element. \*****************************************************************************/ template ElemType CStackType::Top( void ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); ASSERT( !IsEmpty() ); ElemType elem; if( m_Count <= m_cStaticSize ) { // Element from static array. elem = m_StaticArray[m_Count - 1]; } else { // Element from stack node. if( m_pTopNode->IsEmpty() ) { // Top node empty - proceed to next one. ASSERT( m_pTopNode->GetParentNode() ); elem = m_pTopNode->GetParentNode()->Top(); } else { elem = m_pTopNode->Top(); } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return elem; } /*****************************************************************************\ Function: CStack::IsEmpty Description: Check if stack is empty. Input: Output: bool \*****************************************************************************/ template bool CStackType::IsEmpty( void ) const { return ( m_Count == 0 ); } /*****************************************************************************\ Function: CStack::Contains Description: Check if given element is already on the stack. Input: elem - Element to be checked. Output: bool \*****************************************************************************/ template bool CStackType::Contains( const ElemType& elem ) const { ACQUIRE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); bool found = false; if( m_Count >= m_cStaticSize ) { // Search stack nodes: CStackNode* pNode = m_pTopNode; while( pNode ) { if( pNode->Contains( elem ) ) { // Element found! found = true; break; } pNode = pNode->GetParentNode(); } } if( !found ) { // Search static array: DWORD elemNumber = iSTD::Min( m_cStaticSize, m_Count ); while( elemNumber-- ) { if( m_StaticArray[ elemNumber ] == elem ) { // Element found! found = true; break; } } } RELEASE_DEBUG_MUTEX_READ( m_InstanceNotThreadSafe ); return found; } /*****************************************************************************\ Function: CStack::CStackNode constructor \*****************************************************************************/ template CStackType::CStackNode::CStackNode( DWORD size ) : m_cMaxSize( size ), m_Count( 0 ), m_pElements( NULL ), m_pParentNode( NULL ) { } /*****************************************************************************\ Function: CStack::CStackNode constructor \*****************************************************************************/ template CStackType::CStackNode::CStackNode( DWORD size, CStackNode* pParentNode ) : m_cMaxSize( size ), m_Count( 0 ), m_pElements( NULL ), m_pParentNode( pParentNode ) { } /*****************************************************************************\ Function: CStack::CStackNode destructor \*****************************************************************************/ template CStackType::CStackNode::~CStackNode() { CAllocatorType::Deallocate( m_pElements ); } /*****************************************************************************\ Function: CStack::CStackNode::Initialize Description: Allocate element buffer. Input: Output: bool success \*****************************************************************************/ template bool CStackType::CStackNode::Initialize( void ) { m_pElements = (ElemType*)CAllocatorType::Allocate( sizeof(ElemType) * m_cMaxSize ); return ( m_pElements != NULL ); } /*****************************************************************************\ Function: CStack::CStackNode::Create Description: Create new stack node. Input: size Output: pNewNode \*****************************************************************************/ template bool CStackType::CStackNode::Create( DWORD size, CStackNode*& pNewNode ) { bool success = true; pNewNode = new CStackNode( size ); if( pNewNode ) { pNewNode->Acquire(); success = pNewNode->Initialize(); if( success == false ) { CStackNode::Delete( pNewNode ); } } else { ASSERT(0); success = false; } return success; } /*****************************************************************************\ Function: CStack::CStackNode::Create Description: Create new stack node and attach it to given parent node. Input: size pParentNode Output: pNewNode \*****************************************************************************/ template bool CStackType::CStackNode::Create( DWORD size, CStackNode* pParentNode, CStackNode*& pNewNode ) { bool success = true; pNewNode = new CStackNode( size, pParentNode ); if( pNewNode ) { pNewNode->Acquire(); success = pNewNode->Initialize(); if( success == false ) { CStackNode::Delete( pNewNode ); } } else { ASSERT(0); success = false; } return success; } /*****************************************************************************\ Function: CStack::CStackNode::Delete Description: Delete stack node. Input: pNode Output: \*****************************************************************************/ template void CStackType::CStackNode::Delete( CStackNode*& pNode ) { CObject::SafeRelease( pNode ); pNode = NULL; } /*****************************************************************************\ Function: CStack::CStackNode:: Description: Check if stack node is empty. Input: Output: bool \*****************************************************************************/ template bool CStackType::CStackNode::IsEmpty( void ) const { return ( m_Count == 0 ); } /*****************************************************************************\ Function: CStack::CStackNode::IsFull Description: Check if stack node is full. Input: Output: bool \*****************************************************************************/ template bool CStackType::CStackNode::IsFull( void ) const { ASSERT( m_Count <= m_cMaxSize ); return ( m_Count == m_cMaxSize ); } /*****************************************************************************\ Function: CStack::CStackNode::GetMaxSize Description: Get capacity of this stack node. Input: Output: DWORD m_cMaxSize \*****************************************************************************/ template DWORD CStackType::CStackNode::GetMaxSize( void ) const { return m_cMaxSize; } /*****************************************************************************\ Function: CStack::CStackNode::GetParentNode Description: Get parent stack node. Input: Output: CStackNode* m_pParentNode \*****************************************************************************/ template typename CStackType::CStackNode* CStackType::CStackNode::GetParentNode( void ) const { return m_pParentNode; } /*****************************************************************************\ Function: CStack::CStackNode::Push Description: Push element on the stack node. Input: ElemType element Output: \*****************************************************************************/ template void CStackType::CStackNode::Push(ElemType element) { ASSERT( !IsFull() ); m_pElements[m_Count++] = element; } /*****************************************************************************\ Function: CStack::CStackNode::Pop Description: Pop element from the stack node. Input: Output: ElemType - Top element. \*****************************************************************************/ template ElemType CStackType::CStackNode::Pop( void ) { ASSERT( !IsEmpty() ); return m_pElements[--m_Count]; } /*****************************************************************************\ Function: CStack::CStackNode::Top Description: Get the top element without popping it from the stack node. Input: Output: ElemType - Top element. \*****************************************************************************/ template ElemType CStackType::CStackNode::Top( void ) const { ASSERT( !IsEmpty() ); return m_pElements[m_Count - 1]; } /*****************************************************************************\ Function: CStack::CStackNode::Contains Description: Check if given element is already on the stack. Input: elem - Element to be checked. Output: bool \*****************************************************************************/ template bool CStackType::CStackNode::Contains( const ElemType& elem ) const { DWORD elemNumber = m_Count; while( elemNumber-- ) { if( m_pElements[elemNumber] == elem ) { return true; } } return false; } #undef CALCULATE_NEXT_NODE_SIZE } // namespace iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/StaticBitSet.h000066400000000000000000000225761363533017100251140ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once namespace iSTD { /******************************************************************************\ CStaticBitSet provides standard bitset operations when the bitset size is known at compile time. The number of bits supported is up to the template parameter MaxBits. This gets rounded up to the next DWORD aligned value. The API is the similar to iSTD::CBitSet, but this class will not grow if you access an index higher than what is allocated. Instead, this class will provided a nice blue screen to alert you of the error. It is the client's responsibility to do any bounds checking. Bits indices start at 0. For a CStaticBitSet< 32 >, the size is 32 and the valid range of indicies is 0 through 31. Constructor - Initializes all bits to off. Clear - Turns all bits to off. SetAll - Turns all bits to on. Set - Turns one or more bits on. Unset - Turns one bit off. IsSet - Returns true if a bit is on, false otherwise. \******************************************************************************/ template< DWORD MaxBits > class CStaticBitSet { public: CStaticBitSet( void ); void Clear( void ); void SetAll( void ); void Set( const DWORD index ); void Set( const DWORD index, const DWORD count ); void UnSet( const DWORD index ); bool IsSet( const DWORD index ) const; DWORD BitCount() const; DWORD BitCount( DWORD limit ) const; protected: enum { ArraySize = (MaxBits + sizeof(DWORD)*8 - 1 ) >> 5 }; DWORD GetArrayIndex( const DWORD bitNum ) const { return bitNum >> 5; } DWORD GetBitIndex( const DWORD bitNum ) const { return bitNum & 0x1F; } DWORD BitNumber( const DWORD number ) const { return 1 << number; } DWORD m_bits[ ArraySize ]; #ifdef _DEBUG bool m_debugBits[ MaxBits ]; #endif }; /******************************************************************************\ CStaticBitSet \******************************************************************************/ template< DWORD MaxBits > CStaticBitSet< MaxBits >::CStaticBitSet( void ) { C_ASSERT( MaxBits >= 1 ); Clear(); } /******************************************************************************\ CStaticBitSet::Clear \******************************************************************************/ template< DWORD MaxBits > void CStaticBitSet< MaxBits >::Clear( void ) { SafeMemSet( &m_bits, 0, sizeof( m_bits[ 0 ] ) * ArraySize ); #ifdef _DEBUG for( DWORD ndx = 0; ndx < MaxBits; ndx++ ) { m_debugBits[ ndx ] = false; } #endif } /******************************************************************************\ CStaticBitSet::SetAll \******************************************************************************/ template< DWORD MaxBits > void CStaticBitSet< MaxBits >::SetAll( void ) { SafeMemSet( &m_bits, 0xFF, sizeof( m_bits[ 0 ] ) * ArraySize ); #ifdef _DEBUG for( DWORD ndx = 0; ndx < MaxBits; ndx++ ) { m_debugBits[ ndx ] = true; } #endif } /******************************************************************************\ CStaticBitSet::Set \******************************************************************************/ template< DWORD MaxBits > void CStaticBitSet< MaxBits >::Set( const DWORD index ) { #ifdef _DEBUG ASSERT( IsSet( index ) == m_debugBits[ index ] ); #endif ASSERT( GetArrayIndex( index ) <= ArraySize ); DWORD arrayIndex = GetArrayIndex( index ); DWORD bitIndex = GetBitIndex( index ); m_bits[ arrayIndex ] |= BitNumber( bitIndex ); #ifdef _DEBUG m_debugBits[ index ] = true; #endif } /******************************************************************************\ CStaticBitSet::Set (contiguous version) - Sets a contiguous number of bits that could span multiple DWORDS. Optimized towards setting a contiguous amount of bits that span many DWORDS. This algorithm takes advantage of the property that if you set a contiguous set of bits that span multiple DWORDs, all the DWORDs between the first and last bits can be set to 0xFFFFFFFF. There is not need to calculate which bits need to be set. Only the bits in the first and last DWORDs need to be calculated. Notes: This function is specifically coded for m_bits to be DWORDs. If you change the m_bits type, you will need to change this function. \******************************************************************************/ template< DWORD MaxBits > void CStaticBitSet< MaxBits >::Set( const DWORD index, DWORD count ) { ASSERT( GetArrayIndex( index ) <= ArraySize ); #ifdef _DEBUG for( DWORD ndx = 0; ndx < count; ndx++) { m_debugBits[ index + ndx ] = true; } #endif DWORD arrayIndex = GetArrayIndex( index ); DWORD bitIndex = GetBitIndex( index ); DWORD mask; const DWORD BITS_PER_ELEMENT = 32; if( ( bitIndex + count ) <= BITS_PER_ELEMENT ) // Spans only a single DWORD { // Promote to QWORD due to bug when shifting 0x1 by 32 becomes 0x1 // instead of our desired 0x0. Seems like it is a rotate shift. mask = (((QWORD)1 << count ) - 1 ) << bitIndex; m_bits[ arrayIndex ] |= mask; } else { // Set the bits in the first DWORD mask = (DWORD) (QWORD) ( ( (DWORD) -1 ) << bitIndex ) ; m_bits[ arrayIndex ] |= mask ; arrayIndex++; count = count - ( BITS_PER_ELEMENT - bitIndex ); // Set the bits in the middle DWORDs while( count >= BITS_PER_ELEMENT ) { m_bits[ arrayIndex ] = 0xFFFFFFFF; arrayIndex++; count -= BITS_PER_ELEMENT; } // Set the bits in the last DWORD mask = ( (QWORD)1 << count ) - 1; m_bits[ arrayIndex ] |= mask; } #ifdef _DEBUG for( DWORD ndx = 0; ndx < MaxBits; ndx++) { ASSERT( m_debugBits[ ndx ] == IsSet( ndx ) ); } #endif } /******************************************************************************\ CStaticBitSet::UnSet \******************************************************************************/ template< DWORD MaxBits > void CStaticBitSet< MaxBits >::UnSet( const DWORD index ) { #ifdef _DEBUG ASSERT( IsSet( index ) == m_debugBits[ index ] ); #endif ASSERT( GetArrayIndex( index ) <= ArraySize ); DWORD arrayIndex = GetArrayIndex( index ); DWORD bitIndex = GetBitIndex( index ); m_bits[ arrayIndex ] &= ~BitNumber( bitIndex ); #ifdef _DEBUG m_debugBits[ index ] = false; #endif } /******************************************************************************\ CStaticBitSet::IsSet \******************************************************************************/ template< DWORD MaxBits > bool CStaticBitSet< MaxBits >::IsSet( const DWORD index ) const { ASSERT( GetArrayIndex( index ) <= ArraySize ); DWORD arrayIndex = GetArrayIndex( index ); DWORD bitIndex = GetBitIndex( index ); bool isSet = ( m_bits[ arrayIndex ] & BitNumber( bitIndex ) ) ? true : false; #ifdef _DEBUG ASSERT( isSet == m_debugBits[ index ] ); #endif return isSet; } /******************************************************************************\ CStaticBitSet::BitCount \******************************************************************************/ template< DWORD MaxBits > DWORD CStaticBitSet< MaxBits >::BitCount() const { DWORD bitCount = 0; const DWORD cBitsPerArrayElement = sizeof(m_bits[0]) * 8; DWORD index = ArraySize; while( index-- ) { if( m_bits[ index ] != 0 ) { for( DWORD i = 0; i < cBitsPerArrayElement; i++ ) { if( m_bits[index] & (1< DWORD CStaticBitSet< MaxBits >::BitCount(DWORD limit) const { DWORD bitCount = 0; limit = iSTD::Min( limit, ArraySize-1 ); for( DWORD i=0; i <= limit; i++ ) { if( IsSet( i ) ) { bitCount++; } } return bitCount; } } intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Stream.h000066400000000000000000000274711363533017100240040ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Array.h" #include "Buffer.h" #include "utility.h" #include "MemCopy.h" namespace iSTD { /*****************************************************************************\ Class: CStream Description: Allocates and manages a system memory buffer of unknown size \*****************************************************************************/ template class CStream : public CObject { public: CStream( void ); virtual ~CStream( void ); void* GetSpace( const DWORD dwSize ); void* GetLinearAddress( void ); DWORD GetUsedSpace( void ) const; void SetUsedSpace( DWORD currentSizeUsed ); void PutAllSpace( void ); void* GetSegmentAddress( const DWORD offset, const DWORD size ) const; protected: CDynamicArray*,CAllocatorType> m_StreamArray; CBuffer* m_pCurrentBuffer; DWORD m_StreamBufferCount; CBuffer* m_pStreamBuffer; DWORD m_dwSizeUsed; }; /*****************************************************************************\ Function: CStream Constructor Description: Initializes internal data Input: none Output: none \*****************************************************************************/ template inline CStream::CStream( void ) : CObject(), m_StreamArray(0) { m_pCurrentBuffer = NULL; m_StreamBufferCount = 0; m_pStreamBuffer = NULL; m_dwSizeUsed = 0; } /*****************************************************************************\ Function: CStream Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template inline CStream::~CStream( void ) { const DWORD dwCount = m_StreamArray.GetSize(); for( DWORD i = 0; i < dwCount; i++ ) { CBuffer* pBuffer = m_StreamArray.GetElement(i); SafeDelete( pBuffer ); } SafeDelete( m_pStreamBuffer ); } /*****************************************************************************\ Function: CStream::GetSpace Description: Gets space from the stream Input: const DWORD dwSize - size in bytes Output: void* - linear address of space \*****************************************************************************/ template inline void* CStream::GetSpace( const DWORD dwSize ) { // If this is the first GetSpace call, or if( ( !m_pCurrentBuffer ) || // the size requested is larger than the size available ( dwSize > m_pCurrentBuffer->GetAvailableSpace() ) ) { // Create a new buffer large enough for the requested size m_pCurrentBuffer = new CBuffer(); ASSERT( m_pCurrentBuffer ); if( m_pCurrentBuffer && m_pCurrentBuffer->Allocate( Max( (DWORD)0x1000, dwSize ), sizeof(DWORD) ) ) { // Add the buffer to the array of buffers if( m_StreamArray.SetElement( m_StreamBufferCount, m_pCurrentBuffer ) ) { // Keep track of the number of buffers in the array m_StreamBufferCount++; } else { ASSERT(0); SafeDelete( m_pCurrentBuffer ); m_pCurrentBuffer = NULL; } } else { ASSERT(0); SafeDelete( m_pCurrentBuffer ); m_pCurrentBuffer = NULL; } } if( m_pCurrentBuffer ) { // Keep track of the total size of all buffers m_dwSizeUsed += dwSize; return m_pCurrentBuffer->GetSpace( dwSize ); } else { return NULL; } } /*****************************************************************************\ Function: CStream::GetLinearAddress Description: Gets the contiguous linear address of the entire stream Input: none Output: void* - linear address \*****************************************************************************/ template inline void* CStream::GetLinearAddress( void ) { // If there are buffers in the array that have not yet been combined if( m_StreamBufferCount ) { // Create a new stream buffer large enough for all buffers CBuffer* pStreamBuffer = new CBuffer(); ASSERT( pStreamBuffer ); if( pStreamBuffer && pStreamBuffer->Allocate( m_dwSizeUsed, sizeof(DWORD) ) ) { // If there already exists another stream buffer if( m_pStreamBuffer ) { // Add the contents of the previous buffer to the new one MemCopy( pStreamBuffer->GetSpace( m_pStreamBuffer->GetUsedSpace() ), m_pStreamBuffer->GetLinearAddress(), m_pStreamBuffer->GetUsedSpace() ); SafeDelete( m_pStreamBuffer ); } // For each buffer in the buffer array for( DWORD i = 0; i < m_StreamBufferCount; i++ ) { CBuffer* pBuffer = m_StreamArray.GetElement(i); if( pBuffer ) { // Append the contents of the buffers to the stream buffer MemCopy( pStreamBuffer->GetSpace( pBuffer->GetUsedSpace() ), pBuffer->GetLinearAddress(), pBuffer->GetUsedSpace() ); SafeDelete( pBuffer ); // Remove the buffer from the array m_StreamArray.SetElement( i, NULL ); } } m_pCurrentBuffer = NULL; m_StreamBufferCount = 0; m_pStreamBuffer = pStreamBuffer; } else { ASSERT(0); SafeDelete( pStreamBuffer ); pStreamBuffer = NULL; // If we fail to recombine the buffers into a single linear allocation // then return NULL to indicate the failure return NULL; } } return ( m_pStreamBuffer ) ? m_pStreamBuffer->GetLinearAddress() : NULL; } /*****************************************************************************\ Function: CStream::GetUsedSpace Description: Gets the current size of the stream Input: none Output: DWORD - size in bytes \*****************************************************************************/ template inline DWORD CStream::GetUsedSpace( void ) const { return m_dwSizeUsed; } /*****************************************************************************\ Function: CStream::SetUsedSpace Description: Sets the current size of the stream. Function should be used only to sets smaller size. Input: DWORD - size in bytes Output: none \*****************************************************************************/ template inline void CStream::SetUsedSpace( DWORD currentSizeUsed ) { ASSERT( currentSizeUsed == 0 ); ASSERT( currentSizeUsed < m_dwSizeUsed ); m_dwSizeUsed = currentSizeUsed; } /*****************************************************************************\ Function: CStream::PutAllSpace Description: Puts all space back into the CStream. All space becomes unused. Input: none Output: none \*****************************************************************************/ template inline void CStream::PutAllSpace( void ) { const DWORD dwCount = m_StreamArray.GetSize(); for( DWORD i = 0; i < dwCount; i++ ) { CBuffer* pBuffer = m_StreamArray.GetElement(i); if( pBuffer ) { pBuffer->PutAllSpace(); } } m_dwSizeUsed = 0; if( m_pStreamBuffer ) { m_pStreamBuffer->PutAllSpace(); } } /*****************************************************************************\ Function: CStream::GetSegmentAddress Description: Gets the contiguous linear address a segment of the stream Input: const DWORD offset - the offset in the stream of the segment const DWORD size - the size in bytes of the segment Output: void* - linear address Notes: The address returned is only valid for the segment requested. It should not be expected that memory access outside the returned segment is valid. If a segment straddles more than one stream buffer, then the request will fail. This condition will not happen as long as the user accesses segments in the same location and size in which they were added to the stream using GetSpace calls. \*****************************************************************************/ template inline void* CStream::GetSegmentAddress( const DWORD offset, const DWORD size ) const { DWORD currentOffset = offset; if( m_pStreamBuffer ) { if( currentOffset < m_pStreamBuffer->GetUsedSpace() ) { if( ( currentOffset + size ) <= m_pStreamBuffer->GetUsedSpace() ) { return (BYTE*)m_pStreamBuffer->GetLinearAddress() + offset; } else { // The offset is within the buffer, but the size requested // is too large for a contiguous address ASSERT(0); return NULL; } } else { currentOffset -= m_pStreamBuffer->GetUsedSpace(); } } for( DWORD i = 0; i < m_StreamBufferCount; i++ ) { CBuffer* pBuffer = m_StreamArray.GetElement(i); if( pBuffer ) { if( currentOffset < pBuffer->GetUsedSpace() ) { if( ( currentOffset + size ) <= pBuffer->GetUsedSpace() ) { return (BYTE*)pBuffer->GetLinearAddress() + currentOffset; } else { // The offset is within the buffer, but the size requested // is too large for a contiguous address ASSERT(0); return NULL; } } else { currentOffset -= pBuffer->GetUsedSpace(); } } } // offset not found ASSERT(0); return NULL; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/String.h000066400000000000000000001003451363533017100240070ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #if defined _WIN32 # pragma warning( push ) # pragma warning( disable : 4996 ) #endif #include "utility.h" #include "Debug.h" #include "Object.h" #include "MemCopy.h" #include #include namespace iSTD { /*****************************************************************************\ Class: CString Description: Abstraction class for string manipulation \*****************************************************************************/ template class CString : public CObject { public: CString( void ); CString( size_t growSize ); CString( const CString& str ); CString( const char* str ); virtual ~CString( void ); operator const char* () const; bool operator == ( const CString& str ); bool operator == ( const char* str ); CString& operator = ( const CString& str ); CString& operator = ( const char* str ); CString& operator = ( const bool val ); CString& operator = ( const char val ); CString& operator = ( const short val ); CString& operator = ( const int val ); CString& operator = ( const long val ); CString& operator = ( const float val ); CString& operator = ( const unsigned char val ); CString& operator = ( const unsigned short val ); CString& operator = ( const unsigned int val ); CString& operator = ( const unsigned long val ); const CString operator + ( const CString& str ) const; const CString operator + ( const char* str ) const; const CString operator + ( const bool val ) const; const CString operator + ( const char val ) const; const CString operator + ( const short val ) const; const CString operator + ( const int val ) const; const CString operator + ( const long val ) const; const CString operator + ( const float val ) const; const CString operator + ( const unsigned char val ) const; const CString operator + ( const unsigned short val ) const; const CString operator + ( const unsigned int val ) const; const CString operator + ( const unsigned long val ) const; void operator += ( const CString& str ); void operator += ( const char* str ); void operator += ( const bool val ); void operator += ( const char val ); void operator += ( const short val ); void operator += ( const int val ); void operator += ( const long val ); void operator += ( const float val ); void operator += ( const unsigned char val ); void operator += ( const unsigned short val ); void operator += ( const unsigned int val ); void operator += ( const unsigned long val ); void Set( const char* str ); void SetFormatted( const char* str, ... ); void Append( const char* str ); void AppendFormatted( const char* str, ... ); size_t Length( void ) const; bool IsEmpty( void ) const; void DetachBuffer( void ); protected: char* m_pString; size_t m_Length; size_t m_BufferSize; size_t m_GrowSize; static const size_t s_cStringGrowSize = 128; }; /*****************************************************************************\ Function: CString Constructor Description: Initializes internal data Input: none Output: none \*****************************************************************************/ template inline CString::CString( void ) : CObject() { m_pString = NULL; m_Length = 0; m_BufferSize = 0; m_GrowSize = s_cStringGrowSize; } /*****************************************************************************\ Function: CString Constructor Description: Initializes internal data Input: size_t growSize Output: none \*****************************************************************************/ template inline CString::CString( size_t growSize ) : CObject() { m_pString = NULL; m_Length = 0; m_BufferSize = 0; m_GrowSize = growSize; } template inline CString::CString( const CString& str ) : CObject() { m_pString = NULL; m_Length = 0; m_GrowSize = str.m_GrowSize; Set( str.m_pString ); } template inline CString::CString( const char* str ) : CObject() { m_pString = NULL; m_Length = 0; m_GrowSize = s_cStringGrowSize; Set( str ); } /*****************************************************************************\ Function: CString Destructor Description: Deletes internal data Input: none Output: none \*****************************************************************************/ template inline CString::~CString( void ) { CAllocatorType::Deallocate( m_pString ); m_pString = NULL; m_BufferSize = 0; } /*****************************************************************************\ Function: CString::operator const char* () Description: Casts CString object to const char* Input: none Output: const char* \*****************************************************************************/ template inline CString::operator const char* () const { return m_pString; } /*****************************************************************************\ Function: CString::operator == Description: Compares a CString to this CString Input: const CString& str Output: bool \*****************************************************************************/ template inline bool CString::operator == ( const CString& str ) { if( str && m_pString ) { return ( ::strcmp( m_pString, (const char*)str ) == 0 ); } else { return false; } } /*****************************************************************************\ Function: CString::operator == Description: Compares a char* to this CString Input: const char* str Output: bool \*****************************************************************************/ template inline bool CString::operator == ( const char* str ) { if( str && m_pString ) { return ( ::strcmp( m_pString, str ) == 0 ); } else { return false; } } /*****************************************************************************\ Function: CString::operator = Description: Sets a CString to this CString Input: const CString& str Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const CString& str ) { if( str ) { Set( (const char*)str ); } return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a char* to this CString Input: const char* str Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const char* str ) { Set( str ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a bool to this CString Input: const bool val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const bool val ) { SetFormatted( "%d", val ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a char to this CString Input: const char val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const char val ) { SetFormatted( "%d", val ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a short to this CString Input: const short val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const short val ) { SetFormatted( "%d", val ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a int to this CString Input: const int val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const int val ) { SetFormatted( "%d", val ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a long to this CString Input: const long val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const long val ) { SetFormatted( "%d", val ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a float to this CString Input: const float val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const float val ) { double d = val; SetFormatted( "%f", d ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a unsigned char to this CString Input: const unsigned char val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const unsigned char val ) { SetFormatted( "%u", val ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a unsigned short to this CString Input: const unsigned short val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const unsigned short val ) { SetFormatted( "%u", val ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a unsigned int to this CString Input: const unsigned int val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const unsigned int val ) { SetFormatted( "%u", val ); return *this; } /*****************************************************************************\ Function: CString::operator = Description: Sets a unsigned long to this CString Input: const unsigned long val Output: CString& \*****************************************************************************/ template inline CString& CString::operator = ( const unsigned long val ) { SetFormatted( "%u", val ); return *this; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of two CStrings Input: const CString& str Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const CString& str ) const { CString res( *this ); if( str ) { res.Append( (const char*)str ); } return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and char* Input: const char* str Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const char* str ) const { CString res( *this ); res.Append( str ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and bool Input: const bool val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const bool val ) const { CString res( *this ); res.AppendFormatted( "%d", val ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and char Input: const char val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const char val ) const { CString res( *this ); res.AppendFormatted( "%d", val ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and short Input: const short val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const short val ) const { CString res( *this ); res.AppendFormatted( "%d", val ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and int Input: const int val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const int val ) const { CString res( *this ); res.AppendFormatted( "%d", val ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and long Input: const long val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const long val ) const { CString res( *this ); res.AppendFormatted( "%d", val ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and float Input: const float val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const float val ) const { CString res( *this ); double d = val; res.AppendFormatted( "%f", d ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and unsigned char Input: const unsigned char val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const unsigned char val ) const { CString res( *this ); res.AppendFormatted( "%u", val ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and unsigned short Input: const unsigned short val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const unsigned short val ) const { CString res( *this ); res.AppendFormatted( "%u", val ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and unsigned int Input: const unsigned int val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const unsigned int val ) const { CString res( *this ); res.AppendFormatted( "%u", val ); return res; } /*****************************************************************************\ Function: CString::operator + Description: Returns concatenation of CString and unsigned long Input: const unsigned long val Output: const CString \*****************************************************************************/ template inline const CString CString::operator + ( const unsigned long val ) const { CString res( *this ); res.AppendFormatted( "%u", val ); return res; } /*****************************************************************************\ Function: CString::operator += Description: Appends a CString to this CString Input: const CString& str Output: none \*****************************************************************************/ template inline void CString::operator += ( const CString& str ) { if( str ) { Append( (const char*)str ); } } /*****************************************************************************\ Function: CString::operator += Description: Appends a char* to this CString Input: const char* str Output: none \*****************************************************************************/ template inline void CString::operator += ( const char* str ) { Append( str ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a bool to this CString Input: const bool val Output: none \*****************************************************************************/ template inline void CString::operator += ( const bool val ) { AppendFormatted( "%d", val ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a char to this CString Input: const char val Output: none \*****************************************************************************/ template inline void CString::operator += ( const char val ) { AppendFormatted( "%d", val ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a short to this CString Input: const short val Output: none \*****************************************************************************/ template inline void CString::operator += ( const short val ) { AppendFormatted( "%d", val ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a int to this CString Input: const int val Output: none \*****************************************************************************/ template inline void CString::operator += ( const int val ) { AppendFormatted( "%d", val ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a long to this CString Input: const long val Output: none \*****************************************************************************/ template inline void CString::operator += ( const long val ) { AppendFormatted( "%d", val ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a float to this CString Input: const float val Output: none \*****************************************************************************/ template inline void CString::operator += ( const float val ) { double d = val; AppendFormatted( "%f", d ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a unsigned char to this CString Input: const unsigned char val Output: none \*****************************************************************************/ template inline void CString::operator += ( const unsigned char val ) { AppendFormatted( "%u", val ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a unsigned short to this CString Input: const unsigned short val Output: none \*****************************************************************************/ template inline void CString::operator += ( const unsigned short val ) { AppendFormatted( "%u", val ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a unsigned int to this CString Input: const unsigned int val Output: none \*****************************************************************************/ template inline void CString::operator += ( const unsigned int val ) { AppendFormatted( "%u", val ); } /*****************************************************************************\ Function: CString::operator += Description: Appends a unsigned long to this CString Input: const unsigned long val Output: none \*****************************************************************************/ template inline void CString::operator += ( const unsigned long val ) { AppendFormatted( "%u", val ); } /*****************************************************************************\ Function: CString::Set Description: Sets the string to an unformatted string Input: const char* str Output: none \*****************************************************************************/ template void CString::Set( const char* str ) { if( str ) { const size_t length = ::strlen( str ) + 1; CAllocatorType::Deallocate( m_pString ); m_pString = NULL; m_BufferSize = 0; m_pString = (char*)CAllocatorType::Allocate( length ); ASSERT( m_pString ); if( m_pString ) { STRCPY( m_pString, length, str ); m_Length = ::strlen( m_pString ); m_BufferSize = length; } } } /*****************************************************************************\ Function: CString::SetFormatted Description: Sets the string to a formatted string Input: const char* str ... Output: none \*****************************************************************************/ template void CString::SetFormatted( const char* str, ... ) { if( str ) { va_list args; va_start( args, str ); const size_t length = ::_vscprintf( str, args ) + 1; va_end( args ); CAllocatorType::Deallocate( m_pString ); m_pString = NULL; m_BufferSize = 0; m_pString = (char*)CAllocatorType::Allocate( length ); ASSERT( m_pString ); if( m_pString ) { va_start( args, str ); VSNPRINTF( m_pString, length, length, str, args ); va_end( args ); m_Length = ::strlen( m_pString ); m_BufferSize = length; } } } /*****************************************************************************\ Function: CString::Append Description: Appends an unformatted string Input: const char* str Output: none \*****************************************************************************/ template inline void CString::Append( const char* str ) { if( str ) { if( m_pString ) { size_t length = m_Length + ::strlen( str ) + 1; if( length > m_BufferSize ) { // Once appended, it is likely to be appended again // so reserve m_GrowSize bytes extra length += m_GrowSize; char* temp = (char*)CAllocatorType::Allocate( length ); ASSERT( temp ); if( temp ) { STRCPY( temp, length, m_pString ); STRCAT( temp, length, str ); CAllocatorType::Deallocate( m_pString ); m_pString = temp; m_Length = ::strlen( m_pString ); m_BufferSize = length; } } else { STRCAT( m_pString, m_BufferSize, str ); m_Length = ::strlen( m_pString ); } } else { Set( str ); } } } /*****************************************************************************\ Function: CString::AppendFormatted Description: Appends a formatted string Input: const char* str ... Output: none \*****************************************************************************/ template inline void CString::AppendFormatted( const char* str, ... ) { if( str ) { va_list args; va_start( args, str ); size_t length = ::_vscprintf( str, args ) + 1; va_end( args ); if( m_pString != NULL ) { if( (m_Length + length) > m_BufferSize ) { // Once appended, it is likely to be appended again // so reserve m_GrowSize bytes extra length += m_GrowSize; char* temp = (char*)CAllocatorType::Allocate( m_Length + length ); ASSERT( temp ); if( temp ) { MemCopy( temp, m_pString, m_Length ); va_start( args, str ); VSNPRINTF( temp + m_Length, length, length - m_GrowSize, str, args ); va_end( args ); char *oldStr = m_pString; m_pString = temp; m_BufferSize = m_Length + length; m_Length += ::strlen( m_pString + m_Length ); CAllocatorType::Deallocate( oldStr ); } } else { va_start( args, str ); VSNPRINTF( m_pString + m_Length, m_BufferSize - m_Length, length, str, args ); va_end( args ); m_Length += ::strlen( m_pString + m_Length ); } } else //if( m_pString != NULL ) { m_BufferSize = 0; m_pString = (char*)CAllocatorType::Allocate( length ); ASSERT( m_pString != NULL ); if( m_pString ) { va_start( args, str ); VSNPRINTF( m_pString, length, length, str, args ); va_end( args ); m_Length = ::strlen( m_pString ); m_BufferSize = length; } } } } /*****************************************************************************\ Function: CString::Length Description: Returns the length of the string Input: none Output: size_t \*****************************************************************************/ template size_t CString::Length( void ) const { return m_Length; } /*****************************************************************************\ Function: CString::IsEmpty Description: Returns true if, and only if, m_Length is 0. Input: none Output: true if string's length is 0, false if string's length is greater than 0. \*****************************************************************************/ template bool CString::IsEmpty( void ) const { return ( m_Length == 0 ); } /*****************************************************************************\ Function: CString::DetachBuffer Description: Enforces the CString to forget about its previous buffer and do not try to deallocate it. Use carefully and make sure that someone will deallocate this buffer. Input: none Output: none \*****************************************************************************/ template void CString::DetachBuffer( void ) { m_pString = NULL; } } // iSTD #if defined _WIN32 # pragma warning ( pop ) #endif intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Threading.h000066400000000000000000000432001363533017100244420ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #ifdef ISTDLIB_MT #ifdef WIN32_NO_STATUS #undef WIN32_NO_STATUS #include #define WIN32_NO_STATUS #endif #endif #ifdef _WIN32 # include "types.h" # include # include #endif // _WIN32 namespace iSTD { #ifdef _WIN32 /*****************************************************************************\ Critical Section types \*****************************************************************************/ #ifdef ISTDLIB_MT #define DECL_CRITICAL_SECTION(x) CRITICAL_SECTION x #define INIT_CRITICAL_SECTION(x) ::InitializeCriticalSection( &(x) ) #define DELETE_CRITICAL_SECTION(x) ::DeleteCriticalSection( &(x) ) #define ENTER_CRITICAL_SECTION(x) ::EnterCriticalSection( &(x) ) #define LEAVE_CRITICAL_SECTION(x) ::LeaveCriticalSection( &(x) ) #else #define DECL_CRITICAL_SECTION(x) #define INIT_CRITICAL_SECTION(x) #define DELETE_CRITICAL_SECTION(x) #define ENTER_CRITICAL_SECTION(x) #define LEAVE_CRITICAL_SECTION(x) #endif /*****************************************************************************\ Critical Section debug \*****************************************************************************/ // The following macros are used to allow synchronizing a function // to debug multithreading issues due to re-entrancy #define ENABLE_THREADED_FUNCTION_SYNC FALSE #if defined(ISTDLIB_MT) && ENABLE_THREADED_FUNCTION_SYNC // Structure to store data struct THREADED_FUNCTION_DATA { // switch to enable\disable synchronizing a function to debug // possible threading issues. intended to be toggled manually // using the debugger. always disabled by default. bool IsEnabled; // critical section data to synchronize function DECL_CRITICAL_SECTION( CS ); // default constructor to initialize data THREADED_FUNCTION_DATA() { IsEnabled = false; INIT_CRITICAL_SECTION( CS ); }; // default destructor to clean-up data ~THREADED_FUNCTION_DATA() { DELETE_CRITICAL_SECTION( CS ); }; }; // Macro for entry-point of threaded function // Each function has a unique (static) enable and critical section #define THREADED_FUNCTION_ENTER \ static iSTD::THREADED_FUNCTION_DATA sTFD; \ if( sTFD.IsEnabled ) \ { \ ENTER_CRITICAL_SECTION( sTFD.CS ); \ } // Macro for exit-point of threaded function #define THREADED_FUNCTION_EXIT \ if( sTFD.IsEnabled ) \ { \ LEAVE_CRITICAL_SECTION( sTFD.CS ); \ } #else #define THREADED_FUNCTION_ENTER #define THREADED_FUNCTION_EXIT #endif /*****************************************************************************\ Mutex debug \*****************************************************************************/ // The following macros are used to check that classes\functions that are not // re-entrant, are never executed concurently for a single instance #define ENABLE_DEBUG_MUTEX FALSE #if defined(ISTDLIB_MT) && ENABLE_DEBUG_MUTEX // Structure to store data needed by the debug mutex macros // 1) a mutex handle to ensure only a single thread exists between Acquire and Release // 2) a counter for the number of threads trying to enter struct DEBUG_MUTEX_DATA { HANDLE Mutex; (unsigned __int64*) pCounter; }; // Declare the data structure #define DECL_DEBUG_MUTEX(x) iSTD::DEBUG_MUTEX_DATA x // Initialize the debug mutex data // Read Access counter is x.pCounter[0] // Write Access counter is x.pCounter[1] #define INIT_DEBUG_MUTEX(x) \ { \ x.Mutex = ::CreateMutex( NULL, FALSE, NULL ); \ x.pCounter = (unsigned __int64*)::_aligned_malloc( \ 2 * sizeof(unsigned __int64), sizeof(unsigned __int64) ); \ x.pCounter[0] = 0; \ x.pCounter[1] = 0; \ } // Clean-up the debug mutex data #define DELETE_DEBUG_MUTEX(x) \ { \ ::CloseHandle( x.Mutex ); \ ::_aligned_free( x.pCounter ); \ } // Increment the counter of the number of threads entering with read access // Acquire the mutex and break if another thread is waiting for write access #define ACQUIRE_DEBUG_MUTEX_READ(x) \ { \ ::InterlockedIncrement( (unsigned __int64*)&( x.pCounter[0] ) ); \ while( WAIT_OBJECT_0 != ::WaitForSingleObject( x.Mutex, 1 ) ) \ if ( 0 != ::InterlockedOr( (unsigned __int64*)&( x.pCounter[1] ), 0 ) ) \ __debugbreak(); \ } // Break if there is another thread waiting for write access // Decrement read access counter // Release the mutex #define RELEASE_DEBUG_MUTEX_READ(x) \ { \ if( 0 != ::InterlockedOr( (unsigned __int64*)&( x.pCounter[1] ), 0 ) ) \ __debugbreak(); \ ::InterlockedDecrement( (unsigned __int64*)&( x.pCounter[0] ) ); \ ::ReleaseMutex( x.Mutex ); \ } // Increment the counter of the number of threads entering with write access // Acquire the mutex and break if another thread owns the mutex #define ACQUIRE_DEBUG_MUTEX_WRITE(x) \ { \ ::InterlockedIncrement( (unsigned __int64*)&( x.pCounter[1] ) ); \ while( WAIT_OBJECT_0 != ::WaitForSingleObject( x.Mutex, 1 ) ) \ __debugbreak(); \ } // Break if there is another thread waiting for read access // Decrement the counter and break if there is another thread waiting for write access // Release the mutex #define RELEASE_DEBUG_MUTEX_WRITE(x) \ { \ if( 0 != ::InterlockedOr( (unsigned __int64*)&( x.pCounter[0] ), 0 ) ) \ __debugbreak(); \ if( 0 != ::InterlockedDecrement( (unsigned __int64*)&( x.pCounter[1] ) ) ) \ __debugbreak(); \ ::ReleaseMutex( x.Mutex ); \ } #else #define DECL_DEBUG_MUTEX(x) #define INIT_DEBUG_MUTEX(x) #define DELETE_DEBUG_MUTEX(x) #define ACQUIRE_DEBUG_MUTEX_READ(x) #define RELEASE_DEBUG_MUTEX_READ(x) #define ACQUIRE_DEBUG_MUTEX_WRITE(x) #define RELEASE_DEBUG_MUTEX_WRITE(x) #endif #ifdef ISTDLIB_MT /*****************************************************************************\ Thread Management types \*****************************************************************************/ // These are heavy-weight threads; consider using Thread-Pools instead #define THREAD_ARGUMENT void* typedef unsigned int (__stdcall *THREAD_FUNCTION)( THREAD_ARGUMENT ); #ifdef ISTDLIB_MT #define THREAD_HANDLE HANDLE #else struct THREAD_DATA { THREAD_FUNCTION func; THREAD_ARGUMENT arg; }; #define THREAD_HANDLE THREAD_DATA* #endif /*****************************************************************************\ Function: CreateThreads Input: const DWORD numThreads - number of threads to create THREAD_FUNCTION func - pointer to function to execute THREAD_ARGUMENT* args - array of per-thread arguments Output: THREAD_HANDLE* threads - array of per-thread handles THREAD_HANDLE* beginEvents - array of per-thread events to signal the thread to begin THREAD_HANDLE* endEvents - array of per-thread events the thread sets when complete HRESULT \*****************************************************************************/ inline HRESULT CreateThreads( const DWORD numThreads, THREAD_FUNCTION func, THREAD_ARGUMENT* args, THREAD_HANDLE* threads, THREAD_HANDLE* beginEvents, THREAD_HANDLE* endEvents ) { HRESULT hr = S_OK; for( DWORD i = 0; i < numThreads; ++i ) { #ifdef ISTDLIB_MT beginEvents[i] = ::CreateEvent( NULL, FALSE, FALSE, NULL ); endEvents[i] = ::CreateEvent( NULL, FALSE, FALSE, NULL ); threads[i] = ( THREAD_HANDLE )::_beginthreadex( NULL, 0, func, args[i], CREATE_SUSPENDED, NULL ); if( threads[i] ) { ::ResumeThread( threads[i] ); } else { hr = E_FAIL; } #else threads[i] = (THREAD_DATA*)malloc( sizeof(THREAD_DATA) ); if( threads[i] ) { threads[i]->func = func; threads[i]->arg = args[i]; beginEvents[i] = threads[i]; endEvents[i] = NULL; } else { hr = E_FAIL; } #endif } return hr; } /*****************************************************************************\ StartThreads \*****************************************************************************/ inline void StartThreads( const DWORD numThreads, THREAD_HANDLE* beginEvents ) { for( DWORD i = 0; i < numThreads; ++i ) { #ifdef ISTDLIB_MT ::SetEvent( beginEvents[i] ); #else beginEvents[i]->func( beginEvents[i]->arg ); #endif } } /*****************************************************************************\ WaitForThreads \*****************************************************************************/ inline void WaitForThreads( const DWORD numThreads, THREAD_HANDLE* endEvents ) { #ifdef ISTDLIB_MT #ifdef _DEBUG // deadlock detection DWORD result = 0; do { result = ::WaitForMultipleObjects( numThreads, endEvents, TRUE, 1000 ); result &= 0xfffffff0; ASSERT( WAIT_OBJECT_0 == result ); } while( WAIT_OBJECT_0 != result ); #else ::WaitForMultipleObjects( numThreads, endEvents, TRUE, INFINITE ); #endif #endif } /*****************************************************************************\ DeleteThreads \*****************************************************************************/ inline void DeleteThreads( const DWORD numThreads, THREAD_HANDLE* threads, THREAD_HANDLE* beginEvents, THREAD_HANDLE* endEvents ) { for( DWORD i = 0; i < numThreads; ++i ) { #ifdef ISTDLIB_MT ::CloseHandle( threads[i] ); ::CloseHandle( endEvents[i] ); ::CloseHandle( beginEvents[i] ); #else free( threads[i] ); threads[i] = NULL; endEvents[i] = NULL; beginEvents[i] = NULL; #endif } } /*****************************************************************************\ Thread-Pool Management types \*****************************************************************************/ #if defined(ISTDLIB_MT) && (_WIN32_WINNT >= 0x0600) // Minimum supported client: Windows Vista (_WIN32_WINNT_VISTA = 0x0600) /*****************************************************************************\ Function: CreateThreadPool Description: Creates a thread pool Input: PTP_CALLBACK_ENVIRON ptrPoolEnv - pointer to storage where thread pool environment will be stored DWORD minThreads - minimum number of requested threads in the thread pool. DWORD maxThreads - maximum number of requested threads in the thread pool. Output: BOOL - Success or Fail Notes: Client is responsible for management of PTP_CALLBACK_ENVIRON memory \*****************************************************************************/ inline BOOL CreateThreadPool( PTP_CALLBACK_ENVIRON ptrPoolEnv, const DWORD minThreads, const DWORD maxThreads ) { if( ptrPoolEnv ) { InitializeThreadpoolEnvironment( ptrPoolEnv ); PTP_POOL ptrPool = CreateThreadpool( NULL ); if( ptrPool ) { SetThreadpoolThreadMinimum( ptrPool, minThreads ); SetThreadpoolThreadMaximum( ptrPool, maxThreads ); SetThreadpoolCallbackRunsLong( ptrPoolEnv ); SetThreadpoolCallbackPool( ptrPoolEnv, ptrPool ); return TRUE; } } return FALSE; } /*****************************************************************************\ Function: CreateThreadPool Description: Creates a thread pool Input: PTP_CALLBACK_ENVIRON ptrPoolEnv - pointer to storage where thread pool environment will be stored Output: BOOL - Success or Fail Notes: Client is responsible for management of PTP_CALLBACK_ENVIRON memory \*****************************************************************************/ inline BOOL CreateThreadPool( PTP_CALLBACK_ENVIRON ptrPoolEnv ) { SYSTEM_INFO si = { 0 }; ::GetSystemInfo( &si ); return CreateThreadPool( ptrPoolEnv, si.dwNumberOfProcessors, si.dwNumberOfProcessors ); } /*****************************************************************************\ Function: DeleteThreadPool Description: Deletes a thread pool Input: PTP_CALLBACK_ENVIRON ptrPoolEnv - pointer to storage where thread pool environment is stored Output: none Notes: Client is responsible for management of PTP_CALLBACK_ENVIRON memory \*****************************************************************************/ inline void DeleteThreadPool( PTP_CALLBACK_ENVIRON ptrPoolEnv ) { if( ptrPoolEnv ) { if( ptrPoolEnv->Pool ) { CloseThreadpool( ptrPoolEnv->Pool ); } } } /*****************************************************************************\ Function: CreateThreadPoolWork Description: Creates a thread pool work item Input: PTP_WORK_CALLBACK pWorkFunc - pointer to function to add to thread pool PVOID pWorkData - optional data to pass to function PTP_CALLBACK_ENVIRON ptrPoolEnv - thread pool environment Output: PTP_WORK - pointer to work item \*****************************************************************************/ inline PTP_WORK CreateThreadPoolWork( PTP_WORK_CALLBACK pWorkFunc, PVOID pWorkData, PTP_CALLBACK_ENVIRON ptrPoolEnv ) { return CreateThreadpoolWork( pWorkFunc, pWorkData, ptrPoolEnv ); } /*****************************************************************************\ Function: SubmitThreadPoolWork Description: Submits a thread pool work item to the thread pool Input: PTP_WORK - pointer to work item Output: none \*****************************************************************************/ inline void SubmitThreadPoolWork( PTP_WORK pWorkItem ) { if( pWorkItem ) { SubmitThreadpoolWork( pWorkItem ); } } /*****************************************************************************\ Function: WaitForThreadPoolWork Description: Waits for the thread pool work item to complete Input: PTP_WORK ptrWork - pointer to work item Output: none \*****************************************************************************/ inline void WaitForThreadPoolWork( PTP_WORK ptrWork ) { if( ptrWork ) { WaitForThreadpoolWorkCallbacks( ptrWork, FALSE ); } } /*****************************************************************************\ Function: DeleteThreadPoolWork Description: Deletes the thread pool work item to complete Input: PTP_WORK ptrWork - pointer to work item Output: none \*****************************************************************************/ inline void DeleteThreadPoolWork( PTP_WORK& ptrWork ) { if( ptrWork ) { CloseThreadpoolWork( ptrWork ); ptrWork = NULL; } } #endif //defined(ISTDLIB_MT) && (_WIN32_WINNT >= 0x0600) #endif //ISTDLIB_MT #else // _WIN32 #define THREADED_FUNCTION_ENTER #define THREADED_FUNCTION_EXIT #define DECL_CRITICAL_SECTION(x) #define INIT_CRITICAL_SECTION(x) #define DELETE_CRITICAL_SECTION(x) #define ENTER_CRITICAL_SECTION(x) #define LEAVE_CRITICAL_SECTION(x) #define DECL_DEBUG_MUTEX(x) #define INIT_DEBUG_MUTEX(x) #define DELETE_DEBUG_MUTEX(x) #define ACQUIRE_DEBUG_MUTEX_READ(x) #define RELEASE_DEBUG_MUTEX_READ(x) #define ACQUIRE_DEBUG_MUTEX_WRITE(x) #define RELEASE_DEBUG_MUTEX_WRITE(x) #endif // _WIN32 } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Timestamp.h000066400000000000000000000112111363533017100244750ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "types.h" #if defined _WIN32 # include # include # include #else # include # include # ifndef NSEC_PER_SEC # define NSEC_PER_SEC 1000000000L # endif #endif namespace iSTD { /*****************************************************************************\ Inline Function: Pause Description: executes __asm pause \*****************************************************************************/ __forceinline void Pause( void ) { _mm_pause(); } #if defined _WIN32 /*****************************************************************************\ Inline Function: GetTimestampCounter Description: Returns the number of CPU clock cycles since the last reset. \*****************************************************************************/ __forceinline QWORD GetTimestampCounter( void ) { #ifdef ISTDLIB_UMD { QWORD count = 0; ::QueryPerformanceCounter( (LARGE_INTEGER*)&count ); return count; } #else // !ISTDLIB_UMD { #ifdef _WIN64 { return __rdtsc(); } #else // !_WIN64 { __asm rdtsc; } #endif // _WIN64 } #endif // ISTDLIB_UMD } /*****************************************************************************\ Inline Function: GetTimestampFrequency Description: Returns the frequency of the CPU clock cycles \*****************************************************************************/ __forceinline QWORD GetTimestampFrequency( void ) { #ifdef ISTDLIB_UMD { QWORD frequency = 0; ::QueryPerformanceFrequency( (LARGE_INTEGER*)&frequency ); return frequency; } #else // !ISTDLIB_UMD { // Note: Use the following for Conroe 2.4GHz // return 2394050000; return 0; } #endif // ISTDLIB_UMD } /*****************************************************************************\ Inline Function: Wait Description: Waits for some number of milliseconds to complete \*****************************************************************************/ __forceinline void Wait( const DWORD milliseconds ) { const QWORD clocksPerSecond = GetTimestampFrequency(); const QWORD clocksPerMilliSecond = ( clocksPerSecond > 1000 ) ? clocksPerSecond / 1000 : 1; const QWORD clocks = milliseconds * clocksPerMilliSecond; const QWORD start = GetTimestampCounter(); while( clocks < ( GetTimestampCounter() - start ) ) { Pause(); }; } #else /*****************************************************************************\ Inline Function: GetTimestampCounter Description: Returns the value of high resolution performance counter \*****************************************************************************/ __forceinline QWORD GetTimestampCounter( void ) { struct timespec time; clock_gettime(CLOCK_MONOTONIC, &time); return (QWORD)time.tv_nsec + (QWORD)time.tv_sec * (QWORD)NSEC_PER_SEC; } /*****************************************************************************\ Inline Function: GetTimestampFrequency Description: Returns the frequency of high resolution performance counter. On Linux/Android we use timer with nsec accuracy \*****************************************************************************/ __forceinline QWORD GetTimestampFrequency( void ) { return NSEC_PER_SEC; } #endif } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/Vector.h000066400000000000000000000121351363533017100240020ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "types.h" #include "Debug.h" namespace iSTD { /*****************************************************************************\ STRUCT: iSTD::SVector4 \*****************************************************************************/ template struct SVector4 { Type X; Type Y; Type Z; Type W; Type& operator[] ( const int i ) { ASSERT( i >= 0 ); ASSERT( i <= 3 ); return( ((Type*)this)[i] ); } const Type& operator[] ( const int i ) const { ASSERT( i >= 0 ); ASSERT( i <= 3 ); return( ((Type*)this)[i] ); } bool operator == ( const SVector4& vector ) const { return ( ( X == vector.X ) && ( Y == vector.Y ) && ( Z == vector.Z ) && ( W == vector.W ) ); } bool operator != ( const SVector4& vector ) const { return ( ( X != vector.X ) || ( Y != vector.Y ) || ( Z != vector.Z ) || ( W != vector.W ) ); } }; // Specialization of iSTD::SVector4 template for Type float : template<> struct SVector4 { float X; float Y; float Z; float W; float& operator[] ( const int i ) { ASSERT( i >= 0 ); ASSERT( i <= 3 ); return( ((float*)this)[i] ); } const float& operator[] ( const int i ) const { ASSERT( i >= 0 ); ASSERT( i <= 3 ); return( ((float*)this)[i] ); } bool operator == ( const SVector4& vector ) const { return ( ( *(DWORD*)&X == *(DWORD*)&vector.X ) && ( *(DWORD*)&Y == *(DWORD*)&vector.Y ) && ( *(DWORD*)&Z == *(DWORD*)&vector.Z ) && ( *(DWORD*)&W == *(DWORD*)&vector.W ) ); } bool operator != ( const SVector4& vector ) const { return ( ( *(DWORD*)&X != *(DWORD*)&vector.X ) || ( *(DWORD*)&Y != *(DWORD*)&vector.Y ) || ( *(DWORD*)&Z != *(DWORD*)&vector.Z ) || ( *(DWORD*)&W != *(DWORD*)&vector.W ) ); } }; /*****************************************************************************\ STRUCT: SVector3 \*****************************************************************************/ template struct SVector3 { Type X; Type Y; Type Z; Type& operator[] ( const int i ) { ASSERT( i >= 0 ); ASSERT( i <= 2 ); return( ((Type*)this)[i] ); } const Type& operator[] ( const int i ) const { ASSERT( i >= 0 ); ASSERT( i <= 2 ); return( ((Type*)this)[i] ); } bool operator == ( const SVector3& vector ) const { return ( ( X == vector.X ) && ( Y == vector.Y ) && ( Z == vector.Z ) ); } bool operator != ( const SVector3& vector ) const { return ( ( X != vector.X ) || ( Y != vector.Y ) || ( Z != vector.Z ) ); } }; // Specialization of SVector3 template for Type float : template<> struct SVector3 { float X; float Y; float Z; float& operator[] ( const int i ) { ASSERT( i >= 0 ); ASSERT( i <= 2 ); return( ((float *)this)[i] ); } const float& operator[] ( const int i ) const { ASSERT( i >= 0 ); ASSERT( i <= 2 ); return( ((float *)this)[i] ); } bool operator == ( const SVector3& vector ) const { return ( ( *(DWORD*)&X == *(DWORD*)&vector.X ) && ( *(DWORD*)&Y == *(DWORD*)&vector.Y ) && ( *(DWORD*)&Z == *(DWORD*)&vector.Z ) ); } bool operator != ( const SVector3& vector ) const { return ( ( *(DWORD*)&X != *(DWORD*)&vector.X ) || ( *(DWORD*)&Y != *(DWORD*)&vector.Y ) || ( *(DWORD*)&Z != *(DWORD*)&vector.Z ) ); } }; } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/cppcompiler.h000066400000000000000000000031531363533017100250550ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #ifndef __CPPCOMPILER_H__ #define __CPPCOMPILER_H__ #if defined(_MSC_VER) #define ALIGN( size ) __declspec(align(size)) #else #include #include #define ALIGN(size) __attribute__((aligned(size))) #if NO_EXCEPTION_HANDLING #define try if (true) #define catch(x) if (false) #endif #endif #endif // __CPPCOMPILER_H__ intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/iStdLib.h000066400000000000000000000040711363533017100240720ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cppcompiler.h" #include "types.h" #include "osinlines.h" #include "Print.h" #include "Debug.h" #include "utility.h" #include "utilitySSE.h" #include "CpuUtil.h" #include "FloatUtil.h" #include "FloatSafe.h" #include "Alloc.h" #include "MemCopy.h" #include "Threading.h" #include "File.h" #include "Timestamp.h" // Clients may choose not to included template classes #ifndef ISTD_DISABLE_OBJECT_TYPES #include "Object.h" #include "Array.h" #include "BinaryTree.h" #include "BitSet.h" #include "FastMask.h" #include "StaticBitSet.h" #include "LinearAllocator.h" #include "Buffer.h" #include "DisjointSet.h" #include "HashTable.h" #include "LinkedList.h" #include "Queue.h" #include "SparseSet.h" #include "Stack.h" #include "LinearStack.h" #include "Stream.h" #include "String.h" #include "Vector.h" #include "LRUSet.h" #include "LruHashTable.h" #endif intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/osinlines.h000066400000000000000000000051441363533017100245450ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #ifndef __OSINLINES_H__ #define __OSINLINES_H__ #ifdef _MSC_VER /*****************************************************************************\ compile-time ASSERT \*****************************************************************************/ #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] #endif // _MSC_VER #if defined(__GNUC__) #include #include #include #include /*****************************************************************************\ String manipulation. \*****************************************************************************/ inline int _vsnprintf( char *buffer, size_t count, const char *msg, va_list args) { va_list args_cpy; // Copy `args' to prevent internal pointer modification from vsnprintf va_copy(args_cpy, args); int len = vsnprintf(buffer, count, msg, args_cpy); va_end(args_cpy); return len; } inline int _vscprintf(const char *msg, va_list args) { char c; va_list args_cpy; // Copy `args' to prevent internal pointer modification from vsnprintf va_copy(args_cpy, args); int len = vsnprintf(&c, 1, msg, args_cpy); va_end(args_cpy); return len; } //from windows stdlib.h (not available by default in gcc) void *_aligned_malloc(size_t _Size, size_t _Alignment); void _aligned_free(void * _Memory); #endif // __GNUC__ #endif //__OSINLINES_H__ intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/types.h000066400000000000000000000227071363533017100237120ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #ifndef ISTDLIB_TYPES_H_INCLUDED #define ISTDLIB_TYPES_H_INCLUDED #include "cppcompiler.h" #include "osinlines.h" /*****************************************************************************\ standard TYPEDEFs (common) \*****************************************************************************/ #if defined(_WIN32) typedef unsigned __int64 QWORD; // 64-bits, 8-bytes typedef unsigned long DWORD; // 32-bits, 4-bytes typedef signed __int64 INT64; // 64-bits, 8-bytes typedef unsigned __int64 UINT64; // 64-bits, 8-bytes typedef unsigned long ULONG; // 32-bits, 4-bytes typedef unsigned int UINT32; // 32-bits, 4-bytes typedef unsigned int UINT; // 32-bits, 4-bytes typedef int INT; // 32-bits, 4-bytes typedef unsigned char BYTE; // 8-bits, 1-byte typedef unsigned short WORD; // 16-bits, 2-bytes #else // if !defined(_WIN32) #include #endif // if !defined(_WIN32) typedef BYTE KILOBYTE[1024]; // 1024-bytes typedef KILOBYTE MEGABYTE[1024]; // 1024-kilobytes typedef MEGABYTE GIGABYTE[1024]; // 1024-megabytes typedef BYTE PAGE[4096]; // 4096-bytes typedef unsigned short HEXWORD[16]; // 256-bits, 32-bytes /*****************************************************************************\ STRUCT: SRange \*****************************************************************************/ #ifdef __cplusplus template struct SRange { Type Min; Type Max; }; template struct SRangeA { Type Min; Type Max; SRangeA( const Type min, const Type max ) { Min = min; Max = max; }; }; #endif #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable: 4201 ) // warning C4201: nonstandard extension used : nameless struct/union #endif /*****************************************************************************\ UNION: VALUE8 \*****************************************************************************/ union VALUE8 { unsigned char u; signed char s; struct { unsigned char l : 4; unsigned char h : 4; }; }; /*****************************************************************************\ UNION: VALUE16 \*****************************************************************************/ union VALUE16 { unsigned short u; signed short s; struct { VALUE8 l; VALUE8 h; }; }; /*****************************************************************************\ UNION: VALUE32 \*****************************************************************************/ union VALUE32 { unsigned int u; signed int s; float f; DWORD d; // Allows creation of VALUE32 from DWORD. struct { VALUE16 l; VALUE16 h; }; }; /*****************************************************************************\ UNION: VALUE64 \*****************************************************************************/ union VALUE64 { UINT64 u; INT64 s; double f; struct { VALUE32 l; VALUE32 h; }; }; /*****************************************************************************\ UNION: FLOAT8 \*****************************************************************************/ union FLOAT8 { struct { DWORD fraction : 4; DWORD exponent : 3; DWORD sign : 1; }; VALUE8 value; FLOAT8() { value.u = 0; }; FLOAT8( unsigned char uVal ) { value.u = uVal; }; FLOAT8( signed char sVal ) { value.s = sVal; }; }; /*****************************************************************************\ UNION: FLOAT16 \*****************************************************************************/ union FLOAT16 { struct { DWORD fraction : 10; DWORD exponent : 5; DWORD sign : 1; }; VALUE16 value; }; /*****************************************************************************\ UNION: FLOAT32 \*****************************************************************************/ union FLOAT32 { struct { DWORD fraction : 23; DWORD exponent : 8; DWORD sign : 1; }; VALUE32 value; // constructors to perform trivial conversions from // long, ulong and float to FLOAT32 union FLOAT32() { value.f = 0.0f; }; FLOAT32( unsigned long uVal ) { value.u = uVal; }; FLOAT32( signed long sVal ) { value.s = sVal; }; FLOAT32( float fVal ) { value.f = fVal; }; #if defined(__GNUC__) // Curently types DWORD and unsigned long differs when using gcc and msvc. FLOAT32( DWORD val) { value.d = val; } #endif // __GNUC__ }; /*****************************************************************************\ UNION: FLOAT64 \*****************************************************************************/ union FLOAT64 { struct { QWORD fraction : 52; QWORD exponent : 11; QWORD sign : 1; }; VALUE64 value; // constructors to perform trivial conversions from // long, ulong and double float to FLOAT64 union FLOAT64() { value.f = 0.0; }; FLOAT64( UINT64 uVal ) { value.u = uVal; }; FLOAT64( INT64 sVal ) { value.s = sVal; }; FLOAT64( double fVal ) { value.f = fVal; }; }; #ifdef _MSC_VER #pragma warning( pop ) // warning C4201: nonstandard extension used : nameless struct/union #endif // TO DO - SRange, SRectangle is GHAL3D-specific, move to separate header? /*****************************************************************************\ STRUCT: SRectangle \*****************************************************************************/ #ifdef __cplusplus template struct SRectangle { SRange X; SRange Y; }; template struct SRectangleA { SRangeA X; SRangeA Y; SRectangleA( const Type xmin, const Type xmax, const Type ymin, const Type ymax ) : X( xmin, xmax ), Y( ymin, ymax ) { }; }; #endif /*****************************************************************************\ MACRO: SIZE8 \*****************************************************************************/ #ifndef SIZE8 #define SIZE8( x ) ((DWORD)( sizeof(x) )) #endif /*****************************************************************************\ MACRO: SIZE16 \*****************************************************************************/ #ifndef SIZE16 #define SIZE16( x ) ((DWORD)( sizeof(x) / sizeof(WORD) )) #endif /*****************************************************************************\ MACRO: SIZE32 \*****************************************************************************/ #ifndef SIZE32 #define SIZE32( x ) ((DWORD)( sizeof(x) / sizeof(DWORD) )) #endif /*****************************************************************************\ MACRO: SIZE64 \*****************************************************************************/ #ifndef SIZE64 #define SIZE64( x ) ((QWORD)( sizeof(x) / sizeof(QWORD) )) #endif /*****************************************************************************\ MACRO: OP_LENGTH \*****************************************************************************/ #ifndef OP_LENGTH #define OP_LENGTH( x ) ((DWORD)(x) - 2 ) #endif /*****************************************************************************\ CONST: BITS_PER_BYTE, BITS_PER_WORD, BITS_PER_DWORD, BITS_PER_QWORD \*****************************************************************************/ const DWORD BITS_PER_BYTE = 8; const DWORD BITS_PER_WORD = BITS_PER_BYTE * sizeof(WORD); const DWORD BITS_PER_DWORD = BITS_PER_BYTE * sizeof(DWORD); const DWORD BITS_PER_QWORD = BITS_PER_BYTE * sizeof(QWORD); #endif intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/utility.h000066400000000000000000001120571363533017100242470ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "types.h" #include "Debug.h" #include #if defined _WIN32 # include #endif #if !defined(_WIN32) # include "../../inc/common/secure_mem.h" # include "../../inc/common/secure_string.h" #endif namespace iSTD { /*****************************************************************************\ MACRO: BIT \*****************************************************************************/ #ifndef BIT #define BIT( n ) ( 1 << (n) ) #endif /*****************************************************************************\ MACRO: MASKED_BIT \*****************************************************************************/ #ifndef MASKED_BIT #define MASKED_BIT( n, enable ) ( 1 << (n + 16) | ((enable) ? 1 : 0) << (n) ) #endif /*****************************************************************************\ MACRO: QWBIT \*****************************************************************************/ #ifndef QWBIT #define QWBIT( n ) ( 1ll << (n) ) #endif /*****************************************************************************\ MACRO: BITMASK PURPOSE: Creates a mask of n bits \*****************************************************************************/ #ifndef BITMASK #define BITMASK( n ) ( ~( (0xffffffff) << (n) ) ) #endif #ifndef BITMASK_RANGE #define BITMASK_RANGE( startbit, endbit ) ( BITMASK( (endbit)+1 ) & ~BITMASK( startbit ) ) #endif /*****************************************************************************\ MACRO: QWBITMASK PURPOSE: Creates a mask of n bits \*****************************************************************************/ #ifndef QWBITMASK #define QWBITMASK( n ) ( ~( (0xffffffffffffffffull) << (n) ) ) #endif #ifndef QWBITMASK_RANGE #define QWBITMASK_RANGE( startbit, endbit ) ( QWBITMASK( (endbit)+1 ) & ~QWBITMASK( startbit ) ) #endif /*****************************************************************************\ MACRO: BITFIELD_RANGE PURPOSE: Calculates the number of bits between the startbit and the endbit (0 based) \*****************************************************************************/ #ifndef BITFIELD_RANGE #define BITFIELD_RANGE( startbit, endbit ) ((endbit)-(startbit)+1) #endif /*****************************************************************************\ MACRO: BITFIELD_BIT PURPOSE: Definition declared for clarity when creating structs \*****************************************************************************/ #ifndef BITFIELD_BIT #define BITFIELD_BIT( bit ) 1 #endif /*****************************************************************************\ MACRO: GETMSB PURPOSE: Checks MSB \*****************************************************************************/ #ifndef GETMSB #define GETMSB( n ) ( \ ( (n) & BIT(31) ) ? 31 : \ ( (n) & BIT(30) ) ? 30 : \ ( (n) & BIT(29) ) ? 29 : \ ( (n) & BIT(28) ) ? 28 : \ ( (n) & BIT(27) ) ? 27 : \ ( (n) & BIT(26) ) ? 26 : \ ( (n) & BIT(25) ) ? 25 : \ ( (n) & BIT(24) ) ? 24 : \ ( (n) & BIT(23) ) ? 23 : \ ( (n) & BIT(22) ) ? 22 : \ ( (n) & BIT(21) ) ? 21 : \ ( (n) & BIT(20) ) ? 20 : \ ( (n) & BIT(19) ) ? 19 : \ ( (n) & BIT(18) ) ? 18 : \ ( (n) & BIT(17) ) ? 17 : \ ( (n) & BIT(16) ) ? 16 : \ ( (n) & BIT(15) ) ? 15 : \ ( (n) & BIT(14) ) ? 14 : \ ( (n) & BIT(13) ) ? 13 : \ ( (n) & BIT(12) ) ? 12 : \ ( (n) & BIT(11) ) ? 11 : \ ( (n) & BIT(10) ) ? 10 : \ ( (n) & BIT(9) ) ? 9 : \ ( (n) & BIT(8) ) ? 8 : \ ( (n) & BIT(7) ) ? 7 : \ ( (n) & BIT(6) ) ? 6 : \ ( (n) & BIT(5) ) ? 5 : \ ( (n) & BIT(4) ) ? 4 : \ ( (n) & BIT(3) ) ? 3 : \ ( (n) & BIT(2) ) ? 2 : \ ( (n) & BIT(1) ) ? 1 : \ ( (n) & BIT(0) ) ? 0 : \ (-1) ) #endif /*****************************************************************************\ MACRO: BITCOUNT PURPOSE: Determines the number of bits needed in a bitmask, given the number of elements to be stored in the mask \*****************************************************************************/ #ifndef BITCOUNT #define BITCOUNT( n ) ( \ ( ((n)-1) & BIT(31) ) ? 32 : \ ( ((n)-1) & BIT(30) ) ? 31 : \ ( ((n)-1) & BIT(29) ) ? 30 : \ ( ((n)-1) & BIT(28) ) ? 29 : \ ( ((n)-1) & BIT(27) ) ? 28 : \ ( ((n)-1) & BIT(26) ) ? 27 : \ ( ((n)-1) & BIT(25) ) ? 26 : \ ( ((n)-1) & BIT(24) ) ? 25 : \ ( ((n)-1) & BIT(23) ) ? 24 : \ ( ((n)-1) & BIT(22) ) ? 23 : \ ( ((n)-1) & BIT(21) ) ? 22 : \ ( ((n)-1) & BIT(20) ) ? 21 : \ ( ((n)-1) & BIT(19) ) ? 20 : \ ( ((n)-1) & BIT(18) ) ? 19 : \ ( ((n)-1) & BIT(17) ) ? 18 : \ ( ((n)-1) & BIT(16) ) ? 17 : \ ( ((n)-1) & BIT(15) ) ? 16 : \ ( ((n)-1) & BIT(14) ) ? 15 : \ ( ((n)-1) & BIT(13) ) ? 14 : \ ( ((n)-1) & BIT(12) ) ? 13 : \ ( ((n)-1) & BIT(11) ) ? 12 : \ ( ((n)-1) & BIT(10) ) ? 11 : \ ( ((n)-1) & BIT(9) ) ? 10 : \ ( ((n)-1) & BIT(8) ) ? 9 : \ ( ((n)-1) & BIT(7) ) ? 8 : \ ( ((n)-1) & BIT(6) ) ? 7 : \ ( ((n)-1) & BIT(5) ) ? 6 : \ ( ((n)-1) & BIT(4) ) ? 5 : \ ( ((n)-1) & BIT(3) ) ? 4 : \ ( ((n)-1) & BIT(2) ) ? 3 : \ ( ((n)-1) & BIT(1) ) ? 2 : \ ( ((n)-1) & BIT(0) ) ? 1 : \ 0 ) #endif /*****************************************************************************\ MACRO: MIN \*****************************************************************************/ #ifndef MIN #define MIN( x, y ) (((x)<=(y))?(x):(y)) #endif /*****************************************************************************\ MACRO: MAX \*****************************************************************************/ #ifndef MAX #define MAX( x, y ) (((x)>=(y))?(x):(y)) #endif /*****************************************************************************\ MACRO: CEIL_DIV \*****************************************************************************/ #ifndef CEIL_DIV #define CEIL_DIV( x, y ) ( 1 + ( ( ( x ) - 1 ) / ( y ) ) ) #endif /*****************************************************************************\ MACRO: STRCAT \*****************************************************************************/ #ifndef STRCAT #define STRCAT( dst, size, src ) strcat_s( (dst), (size), (src) ) #endif /*****************************************************************************\ MACRO: STRNCAT \*****************************************************************************/ #ifndef STRNCAT #if defined(ISTDLIB_KMD) || !defined(_WIN32) #define STRNCAT( dst, size, src, len ) strncat( (dst), (src), (len) ) #else #define STRNCAT( dst, size, src, len ) strncat_s( (dst), (size), (src), (len) ) #endif #endif /*****************************************************************************\ MACRO: WCSNCAT \*****************************************************************************/ #ifndef WCSNCAT #if defined(ISTDLIB_KMD) || !defined(_WIN32) #define WCSNCAT( dst, size, src, len ) wcsncat( (dst), (src), (len) ) #else #define WCSNCAT( dst, size, src, len ) wcsncat_s( (dst), (size), (src), (len) ) #endif #endif /*****************************************************************************\ MACRO: STRCPY \*****************************************************************************/ #ifndef STRCPY #define STRCPY( dst, size, src ) strcpy_s( (dst), (size), (src) ) #endif /*****************************************************************************\ MACRO: SPRINTF \*****************************************************************************/ #ifndef SPRINTF #if defined(ISTDLIB_KMD) || !defined(_WIN32) #define SPRINTF( dst, size, src, args ) sprintf( (dst), (src), (args) ) #else #define SPRINTF( dst, size, src, args ) sprintf_s( (dst), (size), (src), (args) ) #endif #endif /*****************************************************************************\ MACRO: VSNPRINTF \*****************************************************************************/ #ifndef VSNPRINTF #if defined(ISTDLIB_KMD) || !defined(_WIN32) #define VSNPRINTF( dst, size, len, src, args ) _vsnprintf( (dst), (len), (src), (args) ) #else #define VSNPRINTF( dst, size, len, src, args ) _vsnprintf_s( (dst), (size), (len), (src), (args) ) #endif #endif /*****************************************************************************\ MACRO: VSPRINTF \*****************************************************************************/ #ifndef VSPRINTF #if defined(ISTDLIB_KMD) || !defined(_WIN32) #define VSPRINTF( dst, size, src, args ) vsprintf( (dst), (src), (args) ) #else #define VSPRINTF( dst, size, src, args ) vsprintf_s( (dst), (size), (src), (args) ) #endif #endif /*****************************************************************************\ MACRO: MEMCPY \*****************************************************************************/ #ifndef MEMCPY #if defined(__ANDROID__) #define MEMCPY( dst, size, src, args ) memcpy( (dst), (src), (args) ) #elif defined(ISTDLIB_KMD) || !defined(_MSC_VER) #define MEMCPY( dst, size, src, args ) memcpy( (dst), (src), (args) ) #else #define MEMCPY( dst, size, src, args ) memcpy_s( (dst), (size), (src), (args) ) #endif #endif /*****************************************************************************\ MACRO: ARRAY_COUNT \*****************************************************************************/ #ifndef ARRAY_COUNT #define ARRAY_COUNT( x ) ( sizeof( x ) / sizeof( x[ 0 ] ) ) #endif /*****************************************************************************\ Inline Template Function: Swap Description: Swaps the values of two variables of the same type \*****************************************************************************/ template inline void Swap( Type &var0, Type &var1 ) { Type tmp = var0; var0 = var1; var1 = tmp; } /*****************************************************************************\ Inline Template Function: Min Description: Returns the min of the two values \*****************************************************************************/ template __forceinline Type Min( const Type var0, const Type var1 ) { return ( var0 <= var1 ) ? var0 : var1; } /*****************************************************************************\ Inline Template Function: Max Description: Returns the max of the two values \*****************************************************************************/ template __forceinline Type Max( const Type var0, const Type var1 ) { return ( var0 >= var1 ) ? var0 : var1; } /*****************************************************************************\ Inline Template Function: ClampMax Description: Checks the value for Greater than the maximum value. If the value is greater then the maximum then it returns the maximum value. Otherwise, it returns the value. \*****************************************************************************/ template __forceinline Type ClampMax( const Type value, const Type max ) { return ( ( (value) > (max) ) ? (max) : (value) ); } /*****************************************************************************\ Inline Template Function: ClampMin Description: Checks the value for less than the minimum value. If the value is less then the minimum then it returns the minimum value. Otherwise, it returns the value. \*****************************************************************************/ template __forceinline Type ClampMin( const Type value, const Type min ) { return ( ( (value) < (min) ) ? (min) : (value) ); } /*****************************************************************************\ Inline Template Function: Clamp Description: Checks the value for less than the minimum value or greater than the maximum value. If the value is less then the minimum then it returns the minimum value. If the value is greater then the maximum then it returns the maximum value. Otherwise, it returns the value. \*****************************************************************************/ template __forceinline Type Clamp( const Type value, const Type min, const Type max ) { return ClampMin( ClampMax( value, max ), min ); } /*****************************************************************************\ Inline Template Function: CheckLimits Description: Determines if the value is within the specified range \*****************************************************************************/ template __forceinline bool CheckLimits( const Type value, const Type min, const Type max ) { if( ( value < min ) || ( value > max ) ) { ASSERT(0); return false; } return true; } /*****************************************************************************\ Inline Template Function: emul Description: Upconversion Multiply, used for checking overflow. \*****************************************************************************/ template __forceinline t2 emul( t1 a, t1 b ) { return (t2)a*b; } /*****************************************************************************\ Inline Function: bsr64 Description: Intrinsic definition of bit scan reverse for 64bit values. \*****************************************************************************/ #if defined( _WIN64 ) || defined( __x86_64__ ) __forceinline DWORD bsr64( const unsigned long long int mask ) { #if defined _WIN32 DWORD index; _BitScanReverse64( &index, static_cast<_int64>( mask ) ); return static_cast( index ); #elif defined __linux__ return static_cast( 63 - __builtin_clzll( mask ) ); #else DWORD bit = 0; if( mask != 0 ) { bit = 63; while( ( mask & QWBIT(bit) ) == 0 ) { --bit; } } return bit; #endif } #endif // defined( _WIN64 ) || defined( __x86_64__ ) /*****************************************************************************\ Inline Function: bsr Description: Intrinsic definition when not compiler-defined \*****************************************************************************/ __forceinline DWORD bsr( const DWORD mask ) { #if defined _WIN32 DWORD index; _BitScanReverse( &index, mask ); return static_cast(index); #elif defined __linux__ return static_cast( 31 - __builtin_clz( mask ) ); #else DWORD bit = 0; if( mask != 0 ) { bit = 31; while( ( mask & BIT(bit) ) == 0 ) { --bit; } } return bit; #endif } /*****************************************************************************\ Inline Function: bsr64 Description: Intrinsic definition of bit scan forward for 64bit values. \*****************************************************************************/ #if defined( _WIN64 ) || defined( __x86_64__ ) __forceinline DWORD bsf64( const unsigned long long int mask ) { #if defined _WIN32 DWORD index; _BitScanForward64( &index, static_cast<_int64>( mask ) ); return static_cast( index ); #elif defined __linux__ return static_cast( __builtin_ffsll( mask ) - 1 ); #else DWORD bit = 0; if( mask != 0 ) { while( ( mask & QWBIT(bit) ) == 0 ) { ++bit; } } return bit; #endif } #endif // defined( _WIN64 ) || defined( __x86_64__ ) /*****************************************************************************\ Inline Function: bsf Description: Intrinsic definition when not compiler-defined \*****************************************************************************/ __forceinline DWORD bsf( const DWORD mask ) { #if defined _WIN32 DWORD index; _BitScanForward( &index, mask ); return index; #elif defined __linux__ return static_cast( __builtin_ffsl( mask ) - 1 ); #else DWORD bit = 0; if( mask != 0 ) { while( ( mask & BIT(bit) ) == 0 ) { ++bit; } } return bit; #endif } /*****************************************************************************\ Description: Find first zero which identifies the index of the least significant zero bit mask - mask to be checked \*****************************************************************************/ #ifndef FIND_FIRST_0_LSB #define FIND_FIRST_0_LSB( mask ) ( iSTD::bsf(~mask) ) #endif /*****************************************************************************\ Inline Function: clz Description: Count number of leading zeros of the mask \*****************************************************************************/ __forceinline DWORD clz( const DWORD mask ) { DWORD retValue = 32; // bsr returns 0 if the mask is 0 and sets a the ZF flag so handle // 0 special. if( mask != 0 ) { retValue = 31 - bsr( mask ); } return retValue; } /*****************************************************************************\ Inline Function: IsPowerOfTwo Description: Determines if the given value is a power of two. \*****************************************************************************/ template< typename Type > __forceinline bool IsPowerOfTwo( const Type number ) { return ( ( number & ( number - 1 ) ) == 0 ); } /*****************************************************************************\ Inline Function: Round Description: Rounds an unsigned integer to the next multiple of (power-2) size \*****************************************************************************/ template< typename Type1, typename Type2 > __forceinline Type1 Round( const Type1 value, const Type2 size ) { ASSERT( IsPowerOfTwo(size) ); Type1 mask = (Type1)size - 1; Type1 roundedValue = ( value + mask ) & ~( mask ); return roundedValue; } /*****************************************************************************\ Inline Function: RoundDown Description: Rounds an unsigned integer to the previous multiple of (power-2) size \*****************************************************************************/ template< typename Type1, typename Type2 > __forceinline DWORD RoundDown( const Type1 value, const Type2 size ) { ASSERT( IsPowerOfTwo(size) ); Type1 mask = (Type1)size - 1; Type1 roundedValue = value & ~( mask ); return roundedValue; } /*****************************************************************************\ Inline Function: RoundNonPow2 Description: Rounds up to an unsigned integer to the next multiple of size (nonpow2) \*****************************************************************************/ template< typename Type1, typename Type2 > __forceinline Type1 RoundNonPow2( const Type1 value, const Type2 size ) { const Type1 size1 = (Type1)size; const Type1 remainder = ( value % size1 ); Type1 roundedValue = value; if( remainder ) { roundedValue += size1 - remainder; } return roundedValue; } /*****************************************************************************\ Inline Function: RoundDownNonPow2 Description: Rounds an unsigned integer to the previous multiple of size (nonpow2) \*****************************************************************************/ template< typename Type1, typename Type2 > __forceinline DWORD RoundDownNonPow2( const Type1 value, const Type2 size ) { const Type1 size1 = (Type1)size; return (DWORD)(( value / size1 ) * size1); } /*****************************************************************************\ Inline Function: RoundPower2 Description: Rounds an unsigned 32-bit integer to the next power of 2 \*****************************************************************************/ inline DWORD RoundPower2( const DWORD value ) { return IsPowerOfTwo( value ) ? value : 2ul << bsr( value ); } /*****************************************************************************\ Inline Function: RoundPower2 Description: Rounds an unsigned 64-bit integer to the next power of 2 \*****************************************************************************/ inline QWORD RoundPower2( const QWORD value ) { VALUE64 v64 = { value }; if( v64.h.u || ( v64.l.u & BIT(31) ) ) { v64.h.u = RoundPower2( (DWORD)(( v64.l.u ) ? v64.h.u + 1 : v64.h.u) ); v64.l.u = 0; } else { v64.l.u = RoundPower2( (DWORD)(v64.l.u) ); } return v64.u; } /*****************************************************************************\ Inline Function: Log2 Description: Returns the logarithm base two of the passed in number by returning floor( log2( number ) ). Also in the case of Log2(0) the function will return 0. \*****************************************************************************/ inline DWORD Log2( const DWORD value ) { ASSERT( IsPowerOfTwo(value) ); DWORD power2 = 0; while( value && value != (DWORD)BIT(power2) ) { ++power2; } return power2; } /*****************************************************************************\ Inline Function: IsAligned Description: Determines if the given pointer is aligned to the given size \*****************************************************************************/ template< typename Type > __forceinline bool IsAligned( Type * ptr, const size_t alignSize ) { return ( ( (size_t)ptr % alignSize ) == 0 ); } /*****************************************************************************\ Inline Function: IsAligned Description: Determines if the given size is aligned to the given size \*****************************************************************************/ template< typename Type > __forceinline bool IsAligned( Type size, const size_t alignSize ) { return ( ( size % alignSize ) == 0 ); } /*****************************************************************************\ Inline Function: Align Description: Type-safe (power-2) alignment of a pointer. \*****************************************************************************/ template __forceinline Type* Align( Type* const ptr, const size_t alignment ) { ASSERT( IsPowerOfTwo(alignment) ); return (Type*)( ( ((size_t)ptr) + alignment-1 ) & ~( alignment-1 ) ); } /*****************************************************************************\ Inline Function: Align Description: Type-safe (power-2) alignment of a value. \*****************************************************************************/ template __forceinline Type Align( const Type value, const size_t alignment ) { ASSERT( IsPowerOfTwo(alignment) ); Type mask = static_cast(alignment) - 1; return (value + mask) & ~mask; } /*****************************************************************************\ Inline Function: GetAlignmentOffset Description: Returns the size in bytes needed to align the given pointer to the given alignment size \*****************************************************************************/ template __forceinline DWORD GetAlignmentOffset( Type* const ptr, const size_t alignSize ) { ASSERT( alignSize ); DWORD offset = 0; if( IsPowerOfTwo(alignSize) ) { // can recast 'ptr' to DWORD, since offset is DWORD offset = DWORD( UINT_PTR( Align(ptr, alignSize) ) - (UINT_PTR)(ptr) ); } else { const DWORD modulo = (DWORD)(UINT_PTR(ptr) % alignSize); if( modulo ) { offset = (DWORD)alignSize - modulo; } } return offset; } /*****************************************************************************\ Inline Function: GetAlignmentOffset Description: Returns the size in bytes needed to align the given size to the given alignment size \*****************************************************************************/ template __forceinline Type GetAlignmentOffset( const Type size, const size_t alignSize ) { ASSERT( alignSize ); Type offset = 0; if( IsPowerOfTwo(alignSize) ) { offset = Align(size, alignSize) - size; } else { const Type modulo = (Type)( size % alignSize ); if( modulo ) { offset = (Type)alignSize - modulo; } } return offset; } /*****************************************************************************\ Inline Function: MemCompare Description: Templated Exception Handler Memory Compare function \*****************************************************************************/ template inline bool MemCompare( const void* dst, const void* src ) { const UINT64* pSrc = reinterpret_cast(src); const UINT64* pDst = reinterpret_cast(dst); size_t cmpSize = size; // align for sizes larger than 128 due to double clock penalty for mov // if one of the memory access is not 64 bit aligned. See Intel Programming // manual Volume 1, Section 4.1.1 #ifdef _WIN64 if( size > DUAL_CACHE_SIZE ) { // align data to 64 bit if necessary, calculate number of bytes to offset size_t alignSrc = (size_t)( (UINT_PTR)pSrc & ( sizeof(QWORD) - 1 ) ); size_t alignDst = (size_t)( (UINT_PTR)pDst & ( sizeof(QWORD) - 1 ) ); // alignments are power of 2 : 1 byte, 2 bytes, 4 bytes if( alignSrc > 0 && alignDst > 0 ) { cmpSize -= alignDst; // take off our alignment const UINT32* uSrc = reinterpret_cast(pSrc); const UINT32* uDst = reinterpret_cast(pDst); if( alignDst >= sizeof(UINT32) ) { if( (*uSrc - *uDst) != 0 ) { return false; } alignDst -= sizeof(UINT32); uSrc += 1; uDst += 1; } const WORD* wSrc = reinterpret_cast(uSrc); const WORD* wDst = reinterpret_cast(uDst); if( alignDst >= sizeof(WORD) ) { if( (*wSrc - *wDst) != 0 ) { return false; } alignDst -= sizeof(WORD); wSrc += 1; wDst += 1; } const BYTE* bSrc = reinterpret_cast(wSrc); const BYTE* bDst = reinterpret_cast(wDst); if( alignDst >= sizeof(BYTE) ) { if( (*bSrc - *bDst) != 0 ) { return false; } alignDst -= sizeof(BYTE); bSrc += 1; bDst += 1; } pSrc = reinterpret_cast(bSrc); pDst = reinterpret_cast(bDst); } } #endif // compare memory by tier until we find a difference size_t cnt = cmpSize >> 3; for( size_t i = 0; i < cnt; i++ ) { if( (*pSrc - *pDst) != 0 ) { return false; } pSrc += 1; pDst += 1; } cmpSize -= (cnt * sizeof(UINT64)); if( cmpSize == 0 ) { return true; } const UINT32* dSrc = reinterpret_cast(pSrc); const UINT32* dDst = reinterpret_cast(pDst); if( cmpSize >= sizeof(UINT32) ) { if( (*dSrc - *dDst) != 0 ) { return false; } dSrc += 1; dDst += 1; cmpSize -= sizeof(UINT32); } if( cmpSize == 0 ) { return true; } const WORD* wSrc = reinterpret_cast(dSrc); const WORD* wDst = reinterpret_cast(dDst); if( cmpSize >= sizeof(WORD) ) { if( (*wSrc - *wDst) != 0 ) { return false; } wSrc += 1; wDst += 1; cmpSize -= sizeof(WORD); } if (cmpSize == 0 ) { return true; } const BYTE* bSrc = reinterpret_cast(wSrc); const BYTE* bDst = reinterpret_cast(wDst); if( (*bSrc - *bDst) != 0 ) { return false; } return true; } template <> inline bool MemCompare<1>( const void* dst, const void* src ) { return (*(BYTE*)dst == *(BYTE*)src); } template <> inline bool MemCompare<2>( const void* dst, const void* src ) { return (*(WORD*)dst == *(WORD*)src); } template <> inline bool MemCompare<4>( const void* dst, const void* src ) { return (*(UINT32*)dst == *(UINT32*)src); } template <> inline bool MemCompare<8>( const void* dst, const void* src ) { return (*(UINT64*)dst == *(UINT64*)src); } /*****************************************************************************\ Inline Function: IsEqual Description: Compares two values for equality \*****************************************************************************/ template __forceinline bool IsEqual( const Type& a, const Type& b ) { return iSTD::MemCompare( &a, &b ); } /*****************************************************************************\ Inline Function: IsTagComplete Description: Determines is the surface tag has reached completion \*****************************************************************************/ template __forceinline bool IsTagComplete( const Type hwTag, const Type swTag, const Type resTag ) { return ( ( resTag == hwTag ) || ( ( resTag - hwTag ) > ( swTag - hwTag ) ) ); } /*****************************************************************************\ Inline Function: Hash Description: Calculates hash from sequence of 32-bit values. Jenkins 96-bit mixing function with 32-bit feedback-loop and 64-bit state. All magic values are DWORDs of SHA2-256 mixing data: 0x428a2f98 0x71374491 0xb5c0fbcf 0xe9b5dba5 0x3956c25b 0x59f111f1 0x923f82a4 0xab1c5ed5 Could be speed-up by processing 2 or 3 DWORDs at time. \*****************************************************************************/ #define HASH_JENKINS_MIX(a,b,c) \ { \ a -= b; a -= c; a ^= (c>>13); \ b -= c; b -= a; b ^= (a<<8); \ c -= a; c -= b; c ^= (b>>13); \ a -= b; a -= c; a ^= (c>>12); \ b -= c; b -= a; b ^= (a<<16); \ c -= a; c -= b; c ^= (b>>5); \ a -= b; a -= c; a ^= (c>>3); \ b -= c; b -= a; b ^= (a<<10); \ c -= a; c -= b; c ^= (b>>15); \ } inline QWORD Hash( const DWORD *data, DWORD count ) { DWORD a = 0x428a2f98, hi = 0x71374491, lo = 0xb5c0fbcf; while( count-- ) { a ^= *(data++); HASH_JENKINS_MIX( a, hi, lo ); } return (((QWORD)hi)<<32)|lo; } struct HashJenkinsMixReturnAggregate { HashJenkinsMixReturnAggregate(DWORD _a, DWORD _hi, DWORD _lo) : a(_a), hi(_hi), lo(_lo) {} DWORD a; DWORD hi; DWORD lo; }; inline HashJenkinsMixReturnAggregate HashJenkinsMix(DWORD a, DWORD hi, DWORD lo) { HASH_JENKINS_MIX(a, hi, lo); return HashJenkinsMixReturnAggregate(a, hi, lo); } __forceinline void HashNext(DWORD &a, DWORD &hi, DWORD &lo, DWORD data) { a ^= data; HashJenkinsMixReturnAggregate result = HashJenkinsMix(a, hi, lo); a = result.a; hi = result.hi; lo = result.lo; } __forceinline void HashFirst(DWORD &a, DWORD &hi, DWORD &lo, DWORD data) { a = 0x428a2f98, hi = 0x71374491, lo = 0xb5c0fbcf; HashNext(a, hi, lo, data); } /*****************************************************************************\ Inline Function: HashFromBuffer Description: Calculates hash from data buffer. Input: data - pointer to the data buffer count - size of the buffer in bytes \*****************************************************************************/ inline QWORD HashFromBuffer(const char *data, size_t count) { DWORD a = 0x428a2f98, hi = 0x71374491, lo = 0xb5c0fbcf; const DWORD *dataDw = reinterpret_cast(data); size_t countDw = (DWORD)(count / sizeof(DWORD)); while (countDw--) { a ^= *(dataDw++); HASH_JENKINS_MIX(a, hi, lo); } // If buffer size isn't miltiply of DWORD we have to use last bytes to calculate hash if (count % sizeof(DWORD) != 0) { DWORD lastDw = 0; char *lastBytesBuff = reinterpret_cast(&lastDw); const size_t restBytesCount = count % sizeof(DWORD); for (unsigned int i = 0; i < restBytesCount; i++) { lastBytesBuff[i] = data[count - restBytesCount + i]; } a ^= lastDw; HASH_JENKINS_MIX(a, hi, lo); } return (((QWORD)hi) << 32) | lo; } #undef HASH_JENKINS_MIX /*****************************************************************************\ Inline Function: Hash32b Description: Calculates 32 bit hash from 32 bit value. badc0ded hash - self-reversible, 32->32 mapping, good avalanche 4 asm instructions in x86, 0 maps to 0 \*****************************************************************************/ inline DWORD Hash32b( const DWORD value ) { #if defined _WIN32 return ( _byteswap_ulong( value * 0xbadc0ded ) ^ 0xfecacafe ) * 0x649c57e5; #else return ( __builtin_bswap32( value * 0xbadc0ded ) ^ 0xfecacafe ) * 0x649c57e5; #endif } /*****************************************************************************\ Inline Function: Hash32b Description: Calculates 32 bit hash from sequence of 32 bit values. badc0ded hash - self-reversible, 32->32 mapping, good avalanche 4 asm instructions in x86, 0 maps to 0 \*****************************************************************************/ inline DWORD Hash32b( const DWORD *data, DWORD count ) { DWORD hash = 0xdeadf00d; while( count-- ) { hash ^= Hash32b( *( data + count ) ); } return hash; } /*****************************************************************************\ Inline Function: BitCount Description: Returns the number of bits set to 1 in the input 32-bit number. \*****************************************************************************/ inline DWORD BitCount( DWORD v ) { v = v - ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); return (((v + (v >> 4)) & 0x0F0F0F0F) * 0x1010101) >> 24; } /*****************************************************************************\ Inline Function: BitCount64 Description: Returns the number of bits set to 1 in the input 64-bit number. \*****************************************************************************/ inline DWORD BitCount64( unsigned long long v ) { v -= ( v >> 1 ) & 0x5555555555555555ULL; v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL); v = ((v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL) * 0x0101010101010101ULL; return static_cast( v >> 56 ); } /*****************************************************************************\ Inline Function: BitReverse Description: Reverse a 32-bit bitfield in a number. \*****************************************************************************/ inline DWORD BitReverse( DWORD v ) { // swap odd and even bits v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); // swap consecutive pairs v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); // swap nibbles v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); // swap bytes v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); // swap words v = ( v >> 16 ) | ( v << 16); return v; } /*****************************************************************************\ Inline Function: PtrAdd Description: Type-safe addition of a pointer and a scalar (in bytes). \*****************************************************************************/ template __forceinline Type* PtrAdd( Type* ptr, const size_t numBytes ) { return (Type*)( ((BYTE*)ptr) + numBytes ); } /*****************************************************************************\ Inline Function: FixedSIntToInt Description: Converts a fixed signed integer value into a native signed int \*****************************************************************************/ __forceinline int FixedSIntToInt( DWORD value, DWORD size ) { if( value & BIT(size+1) ) { return -1 * (value + 1); } return value; } } // iSTD intel-graphics-compiler-igc-1.0.3627/3d/common/iStdLib/utilitySSE.h000066400000000000000000000053331363533017100246200ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #if defined(_WIN32) #include #else #include #endif #include "types.h" namespace iSTD { /*****************************************************************************\ Inline Function: FastClamp Description: Fast clamping implementation(s) for 4xfloats \*****************************************************************************/ __forceinline void FastClampF( const __m128 &inMins, const __m128 &inMaxs, float* oDest) { // load data to be clamped into 128 register __m128 vals = _mm_loadu_ps(oDest); // clamp vals = _mm_min_ps(inMaxs, _mm_max_ps(vals, inMins)); // load into output _mm_storeu_ps(oDest, vals); } __forceinline void FastClampF( const __m128 &inMins, const __m128 &inMaxs, float* oDest, const float* inSrc ) { // load data to be clamped into 128 register __m128 vals = _mm_loadu_ps(inSrc); // clamp vals = _mm_min_ps(inMaxs, _mm_max_ps(vals, inMins)); // load into output _mm_storeu_ps(oDest, vals); } __forceinline void FastClampF( const __m128 &inMins, const __m128 &inMaxs, float* oDest, const __m128 &inSrc ) { // clamp __m128 vals = _mm_min_ps(inMaxs, _mm_max_ps(inSrc, inMins)); // load into output _mm_storeu_ps(oDest, vals); } } // iSTD intel-graphics-compiler-igc-1.0.3627/CMakeLists.txt000066400000000000000000000007071363533017100220010ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR) add_subdirectory(IGC) list(APPEND IGC__IGC_TARGETS "igc_dll") list(APPEND IGC__IGC_TARGETS "IGA_DLL") list(APPEND IGC__IGC_TARGETS "IGA_EXE") list(APPEND IGC__IGC_TARGETS "fcl_dll") list(APPEND IGC__IGC_TARGETS "opencl-clang-lib") set(IGC__IGC_TARGETS "${IGC__IGC_TARGETS}" PARENT_SCOPE) set(IGC_LIBRARY_NAME "${IGC_LIBRARY_NAME}" PARENT_SCOPE) set(FCL_LIBRARY_NAME "${FCL_LIBRARY_NAME}" PARENT_SCOPE) intel-graphics-compiler-igc-1.0.3627/IGC/000077500000000000000000000000001363533017100176375ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/000077500000000000000000000000001363533017100224025ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/API/000077500000000000000000000000001363533017100230135ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/API/igc.h000066400000000000000000000171601363533017100237330ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #ifndef __IGC_H #define __IGC_H #if defined(_WIN32) #define IGC_API_CALL_TYPE __stdcall #ifdef IGC_EXPORTS #define IGC_API_CALL __declspec(dllexport) IGC_API_CALL_TYPE #else #define IGC_API_CALL __declspec(dllimport) IGC_API_CALL_TYPE #endif #else #define IGC_API_CALL_TYPE #define IGC_API_CALL __attribute__ ((visibility("default"))) IGC_API_CALL_TYPE #endif #if defined(_DEBUG) || defined(_INTERNAL) # define IGC_DEBUG #endif #include #include "../IGC/Compiler/CodeGenPublicEnums.h" // TODO: add all external declarations so that external projects only need // to include this file only. // Definition of integer Registry-key Values // (may merge this into igc_flags.def's macro) enum { // ForcePixelShaderSIMDMode FLAG_PS_SIMD_MODE_DEFAULT = 0, // default is SIMD8 compilation + heuristics to determine if we want to compile SIMD32/SIMD16 FLAG_PS_SIMD_MODE_FORCE_SIMD8 = 1, // Force SIMD8 compilation FLAG_PS_SIMD_MODE_FORCE_SIMD16 = 2, // Force SIMD16 compilation FLAG_PS_SIMD_MODE_FORCE_SIMD32 = 4, // Force SIMD32 compilation }; enum { BIT_CG_SIMD8 = 0b0000000000000001, BIT_CG_SIMD16 = 0b0000000000000010, BIT_CG_SIMD32 = 0b0000000000000100, BIT_CG_SPILL8 = 0b0000000000001000, BIT_CG_SPILL16 = 0b0000000000010000, BIT_CG_SPILL32 = 0b0000000000100000, BIT_CG_RETRY = 0b0000000001000000, BIT_CG_DO_SIMD32 = 0b0000000010000000, BIT_CG_DO_SIMD16 = 0b0000000100000000, }; typedef unsigned short CG_CTX_STATS_t; // shader stat for opt customization typedef struct { uint32_t m_tempCount; uint32_t m_sampler; uint32_t m_inputCount; uint32_t m_dxbcCount; uint32_t m_ConstantBufferCount; IGC::Float_DenormMode m_floatDenormMode16; IGC::Float_DenormMode m_floatDenormMode32; IGC::Float_DenormMode m_floatDenormMode64; } SHADER_STATS_t; typedef struct { CG_CTX_STATS_t m_stats; // record what simd has been generated void* m_pixelShaderGen; // Generated pixel shader output std::string m_savedBitcodeString; // Serialized Bitcode void* m_savedInstrTypes; SHADER_STATS_t m_savedShaderStats; } CG_CTX_t; #define IsRetry(stats) (stats & (BIT_CG_RETRY)) #define DoSimd16(stats) (stats & (BIT_CG_DO_SIMD16)) #define DoSimd32(stats) (stats & (BIT_CG_DO_SIMD32)) #define HasSimd(MODE, stats) (stats & (BIT_CG_SIMD##MODE)) #define HasSimdSpill(MODE, stats) ((stats & (BIT_CG_SIMD##MODE)) && (stats & (BIT_CG_SPILL##MODE))) #define HasSimdNoSpill(MODE, stats) ((stats & (BIT_CG_SIMD##MODE)) && !(stats & (BIT_CG_SPILL##MODE))) #define SetRetry(stats) (stats = (stats | (BIT_CG_RETRY))) #define SetSimd16(stats) (stats = (stats | (BIT_CG_DO_SIMD16))) #define SetSimd32(stats) (stats = (stats | (BIT_CG_DO_SIMD32))) #define SetSimdSpill(MODE, stats) (stats = (stats | (BIT_CG_SIMD##MODE) | (BIT_CG_SPILL##MODE))) #define SetSimdNoSpill(MODE, stats) (stats = (stats | (BIT_CG_SIMD##MODE) & ~(BIT_CG_SPILL##MODE))) typedef enum { FLAG_CG_ALL_SIMDS = 0, FLAG_CG_STAGE1_FAST_COMPILE = 1, FLAG_CG_STAGE1_BEST_PERF = 2, } CG_FLAG_t; #define IsStage2Available(ctx_ptr) (ctx_ptr != nullptr) #define IsStage2RestSIMDs(prev_ctx_ptr) (prev_ctx_ptr != nullptr) #define IsStage1FastCompile(flag, prev_ctx_ptr) (!IsStage2RestSIMDs(prev_ctx_ptr) && flag == FLAG_CG_STAGE1_FAST_COMPILE) #define IsStage1BestPerf(flag, prev_ctx_ptr) (!IsStage2RestSIMDs(prev_ctx_ptr) && flag == FLAG_CG_STAGE1_BEST_PERF) #define IsAllSIMDs(flag, prev_ctx_ptr) (!IsStage2RestSIMDs(prev_ctx_ptr) && flag == FLAG_CG_ALL_SIMDS) #define IsStage1(pCtx) (IsStage1BestPerf(pCtx->m_CgFlag, pCtx->m_StagingCtx) || \ IsStage1FastCompile(pCtx->m_CgFlag, pCtx->m_StagingCtx)) #define HasSavedIR(pCtx) (pCtx && IsStage2RestSIMDs(pCtx->m_StagingCtx) && \ pCtx->m_StagingCtx->m_savedBitcodeString.size() > 0) #define DoSimd32Stage2(prev_ctx_ptr) (IsStage2RestSIMDs(prev_ctx_ptr) && DoSimd32(prev_ctx_ptr->m_stats)) #define DoSimd16Stage2(prev_ctx_ptr) (IsStage2RestSIMDs(prev_ctx_ptr) && DoSimd16(prev_ctx_ptr->m_stats)) // We don't need compile continuation if no staged compilation enabled denoted by RegKeys. // If the staged compilation enabled, we don't need compile continuation when SIMD8 is spilled. #define HasCompileContinuation(flag, prev_ctx_ptr, stats) ( \ IGC_IS_FLAG_ENABLED(StagedCompilation) && \ ((IsStage1FastCompile(flag, prev_ctx_ptr) && \ !(!IsRetry(stats) && !DoSimd16(stats))) || \ ((IsStage1BestPerf(flag, prev_ctx_ptr)) && \ ( IGC_IS_FLAG_ENABLED(ExtraRetrySIMD16) && !HasSimdSpill(8, stats)) || \ (!IGC_IS_FLAG_ENABLED(ExtraRetrySIMD16) && (!HasSimd(8, stats) || DoSimd32(stats))))) \ ) // Return true when simd MODE has been generated previously #define AvoidDupStage2(MODE, flag, prev_ctx_ptr) (IsStage2RestSIMDs(prev_ctx_ptr) && HasSimdNoSpill(MODE, prev_ctx_ptr->m_stats)) // Fast CG always returns simd 8 #define ValidFastModes(flag, prev_ctx_ptr, stats) (IsStage1FastCompile(flag, prev_ctx_ptr) && HasSimd(8, stats) && !HasSimd(16, stats) && !HasSimd(32, stats)) // Best CG returns simd 8 or 16 #define ValidBestModes(flag, prev_ctx_ptr, stats) (IsStage1BestPerf(flag, prev_ctx_ptr) && (HasSimd(8, stats) || HasSimd(16, stats)) && !HasSimd(32, stats)) // ALL_SIMDS CG must have simd 8 in any case #define ValidAllSimdsModes(flag, prev_ctx_ptr, stats) (IsAllSIMDs(flag, prev_ctx_ptr) && HasSimd(8, stats)) // Rest Stage2 CG would not generate duplicated simd 32 or 16 modes, and // When simd 8 spills in Stage1 for FAST_COMPILE, we may generate simd again; // otherwise it must be generated either from Stage1 or Stage2 #define ValidStage2Modes(prev_ctx_ptr, stats) ( \ IsStage2RestSIMDs(prev_ctx_ptr) && \ (!HasSimd(32, prev_ctx_ptr->m_stats) || !HasSimd(32, stats)) && \ (!HasSimd(16, prev_ctx_ptr->m_stats) || !HasSimd(16, stats)) && \ ((HasSimd(8, prev_ctx_ptr->m_stats) ^ HasSimd(8, stats)) || HasSimdSpill(8, prev_ctx_ptr->m_stats)) \ ) #define ValidGeneratedModes(flag, prev_ctx_ptr, stats) ( \ ValidFastModes(flag, prev_ctx_ptr, stats) || \ ValidBestModes(flag, prev_ctx_ptr, stats) || \ ValidAllSimdsModes(flag, prev_ctx_ptr, stats) || \ ValidStage2Modes(prev_ctx_ptr, stats) \ ) #endif // __IGC_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/AddImplicitArgs.cpp000066400000000000000000000724321363533017100261160ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "AddImplicitArgs.hpp" #include "AdaptorCommon/ImplicitArgs.hpp" #include "Compiler/IGCPassSupport.h" #include "Compiler/CISACodeGen/CISACodeGen.h" #include "Compiler/Optimizer/OCLBIUtils.h" #include "LLVM3DBuilder/MetadataBuilder.h" #include "common/LLVMWarningsPush.hpp" #include "llvm/ADT/SCCIterator.h" #include #include #include #include #include #include "llvm/IR/DIBuilder.h" #include "common/LLVMWarningsPop.hpp" #include "Compiler/DebugInfo/VISADebugEmitter.hpp" #include "common/debug/Debug.hpp" #include #include using namespace llvm; using namespace IGC; using namespace IGC::IGCMD; // Register pass to igc-opt #define PASS_FLAG "igc-add-implicit-args" #define PASS_DESCRIPTION "Add implicit args to all functions in the module and adjusts call to these functions" #define PASS_CFG_ONLY false #define PASS_ANALYSIS false IGC_INITIALIZE_PASS_BEGIN(AddImplicitArgs, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS) IGC_INITIALIZE_PASS_DEPENDENCY(CodeGenContextWrapper) IGC_INITIALIZE_PASS_DEPENDENCY(MetaDataUtilsWrapper) IGC_INITIALIZE_PASS_END(AddImplicitArgs, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS) char AddImplicitArgs::ID = 0; AddImplicitArgs::AddImplicitArgs() : ModulePass(ID) { initializeAddImplicitArgsPass(*PassRegistry::getPassRegistry()); } bool AddImplicitArgs::runOnModule(Module &M) { MapList funcsMapping; MapList funcsMappingForReplacement; m_pMdUtils = getAnalysis().getMetaDataUtils(); CodeGenContext* ctx = getAnalysis().getCodeGenContext(); // Update function signatures // Create new functions with implicit args for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { Function* pFunc = &(*I); // Only handle functions defined in this module if (pFunc->isDeclaration()) continue; // skip non-entry functions if (m_pMdUtils->findFunctionsInfoItem(pFunc) == m_pMdUtils->end_FunctionsInfo()) continue; // No implicit arg support for indirect calls if (pFunc->hasFnAttribute("IndirectlyCalled")) continue; // see the detail in StatelessToStatefull.cpp. // If SToSProducesPositivePointer is true, do not generate implicit arguments. if (IGC_IS_FLAG_DISABLED(SToSProducesPositivePointer) && (ctx->getModuleMetaData()->compOpt.HasBufferOffsetArg || IGC_IS_FLAG_ENABLED(EnableSupportBufferOffset))) { ImplicitArgs::addBufferOffsetArgs(*pFunc, m_pMdUtils, ctx->getModuleMetaData()); } ImplicitArgs implicitArgs(*pFunc, m_pMdUtils); // Create the new function body and insert it into the module FunctionType *pNewFTy = getNewFuncType(pFunc, &implicitArgs); Function* pNewFunc = Function::Create(pNewFTy, pFunc->getLinkage()); pNewFunc->copyAttributesFrom(pFunc); pNewFunc->setSubprogram(pFunc->getSubprogram()); M.getFunctionList().insert(pFunc->getIterator(), pNewFunc); pNewFunc->takeName(pFunc); // Since we have now created the new function, splice the body of the old // function right into the new function, leaving the old body of the function empty. pNewFunc->getBasicBlockList().splice(pNewFunc->begin(), pFunc->getBasicBlockList()); // Loop over the argument list, transferring uses of the old arguments over to // the new arguments updateNewFuncArgs(pFunc, pNewFunc, &implicitArgs); // Map old func to new func funcsMapping[pFunc] = pNewFunc; if (!pFunc->use_empty()) { funcsMappingForReplacement[pFunc] = pNewFunc; } } if (IGC_GET_FLAG_VALUE(FunctionControl) != FLAG_FCALL_FORCE_INLINE) { for (auto I : funcsMappingForReplacement) { replaceAllUsesWithNewOCLBuiltinFunction(ctx, I.first, I.second); } } // Update IGC Metadata // Function declarations are changing, this needs to be reflected in the metadata. MetadataBuilder mbuilder(&M); auto &FuncMD = ctx->getModuleMetaData()->FuncMD; for (auto i : funcsMapping) { auto oldFuncIter = m_pMdUtils->findFunctionsInfoItem(i.first); m_pMdUtils->setFunctionsInfoItem(i.second, oldFuncIter->second); m_pMdUtils->eraseFunctionsInfoItem(oldFuncIter); mbuilder.UpdateShadingRate(i.first, i.second); auto loc = FuncMD.find(i.first); if (loc != FuncMD.end()) { auto funcInfo = loc->second; FuncMD.erase(i.first); FuncMD[i.second] = funcInfo; } } m_pMdUtils->save(M.getContext()); //Return if any error if (!(getAnalysis().getCodeGenContext()->oclErrorMessage.empty())) { return false; } // Go over all changed functions for (MapList::const_iterator I = funcsMapping.begin(), E = funcsMapping.end(); I != E; ++I) { Function* pFunc = I->first; assert(pFunc->use_empty() && "Assume all user function are inlined at this point"); // Now, after changing funciton signature, // and validate there are no calls to the old function we can erase it. pFunc->eraseFromParent(); } return true; } FunctionType* AddImplicitArgs::getNewFuncType(Function* pFunc, const ImplicitArgs* pImplicitArgs) { // Add all explicit parameters FunctionType* pFuncType = pFunc->getFunctionType(); std::vector newParamTypes(pFuncType->param_begin(), pFuncType->param_end()); // Add implicit arguments parameter types for(unsigned int i = 0; i < pImplicitArgs->size(); ++i) { newParamTypes.push_back((*pImplicitArgs)[i].getLLVMType(pFunc->getContext())); } // Create new function type with explicit and implicit parameter types return FunctionType::get( pFunc->getReturnType(),newParamTypes, pFunc->isVarArg()); } void AddImplicitArgs::updateNewFuncArgs(llvm::Function* pFunc, llvm::Function* pNewFunc, const ImplicitArgs* pImplicitArgs) { // Loop over the argument list, transferring uses of the old arguments over to // the new arguments, also transferring over the names as well. Function::arg_iterator currArg = pNewFunc->arg_begin(); std::map argMap; std::vector> newAddr; bool fullDebugInfo = false; IF_DEBUG_INFO(bool lineNumbersOnly = false;) IF_DEBUG_INFO(CodeGenContext* ctx = getAnalysis().getCodeGenContext();) IF_DEBUG_INFO(DebugMetadataInfo::hasAnyDebugInfo(ctx, fullDebugInfo, lineNumbersOnly);) if (fullDebugInfo) { unsigned int i = 0; // Create a map storing function arguments of pFunc with their position // of occurrence. for (auto arg = pFunc->arg_begin(); arg != pFunc->arg_end(); ++arg, ++i) { argMap.insert(std::make_pair(&(*arg), i)); } // Iterate over each dbg.declare intrinsic call. If the address operand // matches with any argument from old function, pFunc, store it in a // data structure so we can fix it later. for (auto bb = pNewFunc->begin(); bb != pNewFunc->end(); ++bb) { for (auto inst = bb->begin(); inst != bb->end();) { auto DIInst = dyn_cast_or_null(&(*inst)); if (DIInst) { { auto addr = dyn_cast_or_null(DIInst->getAddress()); if (addr) { if (argMap.find(addr) != argMap.end()) { newAddr.push_back(std::make_pair(DIInst, argMap.find(addr)->second)); } } } } ++inst; } } } for (Function::arg_iterator I = pFunc->arg_begin(), E = pFunc->arg_end(); I != E; ++I, ++currArg) { llvm::Value* newArg = &(*currArg); if ((*I).getType() != currArg->getType()) { // fix opague type mismatch on %opencl.image... std::string str0; llvm::raw_string_ostream s(str0); currArg->getType()->print(s); BasicBlock &entry = pNewFunc->getEntryBlock(); newArg = new llvm::BitCastInst(&(*currArg), (*I).getType(), "", &entry.front()); } // Move the name and users over to the new version. I->replaceAllUsesWith(newArg); currArg->takeName(&(*I)); } // In following loop, fix dbg.declare nodes that reference function arguments. // This occurs for example when a struct type is passed as a kernel parameter // byval. Bug#GD-429 had this exact issue. If we dont do this then we lose // mapping of argument to dbg.declare and elf file comes up with empty // storage location for the variable. for (auto toReplace : newAddr) { unsigned int i = 0; for (auto pNewFuncArg = pNewFunc->arg_begin(); pNewFuncArg != pNewFunc->arg_end(); ++pNewFuncArg, ++i) { if (i != toReplace.second) continue; IF_DEBUG_INFO(auto d = dyn_cast(toReplace.first);) llvm::DIBuilder Builder(*pNewFunc->getParent()); IF_DEBUG_INFO(auto DIVar = d->getVariable();) IF_DEBUG_INFO(auto DIExpr = d->getExpression();) Value* v = dyn_cast_or_null(&(*pNewFuncArg)); if (v) { IF_DEBUG_INFO(Builder.insertDeclare(v, DIVar, DIExpr, d->getDebugLoc().get(), d);) IF_DEBUG_INFO(auto oldInst = d;) IF_DEBUG_INFO(oldInst->eraseFromParent();) } break; } } // Set implict argument names InfoToImpArgMap &infoToArg = m_FuncInfoToImpArgMap[pNewFunc]; ImpArgToExpNum &argImpToExpNum = m_FuncImpToExpNumMap[pNewFunc]; for (unsigned int i = 0; i < pImplicitArgs->size(); ++i, ++currArg) { ImplicitStructArgument info; currArg->setName((*pImplicitArgs)[i].getName()); ImplicitArg::ArgType argId = (*pImplicitArgs)[i].getArgType(); info.DW0.All.argId = argId; info.DW0.All.argExplictNum = 0; info.DW0.All.argOffset = 0; if (argId < ImplicitArg::ArgType::STRUCT_START) { infoToArg[info.DW0.Value] = &(*currArg); } else if (argId <= ImplicitArg::IMAGES_END || argId == ImplicitArg::ArgType::GET_OBJECT_ID || argId == ImplicitArg::ArgType::GET_BLOCK_SIMD_SIZE) { // struct, image FunctionInfoMetaDataHandle funcInfo = m_pMdUtils->getFunctionsInfoItem(pFunc); ArgInfoMetaDataHandle argInfo = funcInfo->getImplicitArgInfoListItem(i); assert(argInfo->isExplicitArgNumHasValue() && "wrong data in MetaData"); info.DW0.All.argExplictNum = argInfo->getExplicitArgNum(); if (argId <= ImplicitArg::ArgType::STRUCT_END) { assert(argInfo->isStructArgOffsetHasValue() && "wrong data in MetaData"); info.DW0.All.argOffset = argInfo->getStructArgOffset(); } infoToArg[info.DW0.Value] = &(*currArg); argImpToExpNum[&(*currArg)] = info.DW0.All.argExplictNum; } else { infoToArg[info.DW0.Value] = &(*currArg); } } } void AddImplicitArgs::replaceAllUsesWithNewOCLBuiltinFunction(CodeGenContext* ctx, llvm::Function* old_func, llvm::Function* new_func) { assert(!old_func->use_empty()); FunctionInfoMetaDataHandle subFuncInfo = m_pMdUtils->getFunctionsInfoItem(old_func); std::vector list_delete; old_func->removeDeadConstantUsers(); std::vector functionUserList(old_func->user_begin(), old_func->user_end()); for (auto U : functionUserList) { CallInst *cInst = dyn_cast(U); auto BC = dyn_cast(U); if (BC && BC->hasOneUse()) cInst = dyn_cast(BC->user_back()); if (IGC_IS_FLAG_ENABLED(EnableFunctionPointer)) { if (!cInst || cInst->getCalledValue() != old_func) { // Support indirect function pointer usages if (Instruction* userInst = dyn_cast(U)) { IRBuilder<> builder(userInst); Value* fncast = builder.CreateBitCast(new_func, old_func->getType()); userInst->replaceUsesOfWith(old_func, fncast); continue; } else if (ConstantExpr *OldExpr = dyn_cast(U)) { Constant* fncast = ConstantExpr::getBitCast(new_func, old_func->getType()); SmallVector NewOps; for (auto Op : OldExpr->operand_values()) { (Op == old_func) ? NewOps.push_back(fncast) : NewOps.push_back(cast(Op)); } auto NewExpr = OldExpr->getWithOperands(NewOps); OldExpr->replaceAllUsesWith(NewExpr); OldExpr->destroyConstant(); continue; } } } if (!cInst) { assert(0 && "Unknown function usage"); getAnalysis().getCodeGenContext()->EmitError(" undefined reference to `jmp()' "); return; } //Return if any error if (!(getAnalysis().getCodeGenContext()->oclErrorMessage.empty())) { return; } std::vector new_args; Function *parent_func = cInst->getParent()->getParent(); size_t numArgOperands = cInst->getNumArgOperands(); // let 's prepare argument list on new call function llvm::Function::arg_iterator new_arg_iter = new_func->arg_begin(); llvm::Function::arg_iterator new_arg_end = new_func->arg_end(); assert(IGCLLVM::GetFuncArgSize(new_func) >= numArgOperands); // basic arguments for (unsigned int i = 0; i < numArgOperands; ++i, ++new_arg_iter) { llvm::Value* arg = cInst->getOperand(i); if (arg->getType() != new_arg_iter->getType()) { // fix opague type mismatch on %opencl... std::string str0; llvm::raw_string_ostream s(str0); arg->getType()->print(s); arg = new llvm::BitCastInst(arg, new_arg_iter->getType(), "", cInst); } new_args.push_back(arg); } // implicit arguments int cImpCount = 0; InfoToImpArgMap &infoToArg = m_FuncInfoToImpArgMap[parent_func]; ImpArgToExpNum &argImpToExpNum = m_FuncImpToExpNumMap[new_func]; while (new_arg_iter != new_arg_end) { ArgInfoMetaDataHandle argInfo = subFuncInfo->getImplicitArgInfoListItem(cImpCount); ImplicitArg::ArgType argId = (ImplicitArg::ArgType)argInfo->getArgId(); ImplicitStructArgument info; info.DW0.All.argId = argId; info.DW0.All.argExplictNum = 0; info.DW0.All.argOffset = 0; if (argId < ImplicitArg::ArgType::STRUCT_START) { assert(infoToArg.find(info.DW0.Value) != infoToArg.end() && "Can't find the implicit argument on parent function"); new_args.push_back(infoToArg[info.DW0.Value]); } else if (argId <= ImplicitArg::ArgType::STRUCT_END) { assert(0 && "wrong argument type in user function"); } else if (argId <= ImplicitArg::IMAGES_END || argId == ImplicitArg::ArgType::GET_OBJECT_ID || argId == ImplicitArg::ArgType::GET_BLOCK_SIMD_SIZE) { // special handling for image info types, such as ImageWidth, ImageHeight, ... // and struct type assert(argImpToExpNum.find(&(*new_arg_iter)) != argImpToExpNum.end() && "Can't find explicit argument number"); // tracing it on parent function argument list Value* callArg = CImagesBI::CImagesUtils::traceImageOrSamplerArgument(cInst, argImpToExpNum[&(*new_arg_iter)]); Argument* arg = dyn_cast(callArg); assert(arg && " Not supported"); // build info info.DW0.All.argExplictNum = arg->getArgNo(); assert(infoToArg.find(info.DW0.Value) != infoToArg.end() && "Can't find the implicit argument on parent function"); new_args.push_back(infoToArg[info.DW0.Value]); } else { assert(infoToArg.find(info.DW0.Value) != infoToArg.end() && "Can't find the implicit argument on parent function"); new_args.push_back(infoToArg[info.DW0.Value]); } ++new_arg_iter; ++cImpCount; } // insert new call instruction before old one llvm::CallInst *inst; if (new_func->getReturnType()->isVoidTy()) { inst = CallInst::Create(new_func, new_args, "", cInst); } else { inst = CallInst::Create(new_func, new_args, new_func->getName(), cInst); } inst->setCallingConv(new_func->getCallingConv()); inst->setDebugLoc(cInst->getDebugLoc()); cInst->replaceAllUsesWith(inst); list_delete.push_back(cInst); } for (auto i : list_delete) { i->eraseFromParent(); } } // Builtin CallGraph Analysis #define PASS_FLAG2 "igc-callgraphscc-analysis" #define PASS_DESCRIPTION2 "Analyzes CallGraphSCC" #define PASS_CFG_ONLY2 false #define PASS_ANALYSIS2 false IGC_INITIALIZE_PASS_BEGIN(BuiltinCallGraphAnalysis, PASS_FLAG2, PASS_DESCRIPTION2, PASS_CFG_ONLY2, PASS_ANALYSIS2) IGC_INITIALIZE_PASS_DEPENDENCY(MetaDataUtilsWrapper) IGC_INITIALIZE_PASS_END(BuiltinCallGraphAnalysis, PASS_FLAG2, PASS_DESCRIPTION2, PASS_CFG_ONLY2, PASS_ANALYSIS2) char BuiltinCallGraphAnalysis::ID = 0; BuiltinCallGraphAnalysis::BuiltinCallGraphAnalysis() : ModulePass(ID) { initializeBuiltinCallGraphAnalysisPass(*PassRegistry::getPassRegistry()); } /// Check whether there are recursions. static bool hasRecursion(CallGraph &CG) { // Use Tarjan's algorithm to detect recursions. for (auto I = scc_begin(&CG), E = scc_end(&CG); I != E; ++I) { const std::vector &SCCNodes = *I; if (SCCNodes.size() >= 2) { return true; } // Check self-recursion. auto Node = SCCNodes.back(); for (auto Callee : *Node) { if (Callee.second == Node) { return true; } } } // No recursion. return false; } bool BuiltinCallGraphAnalysis::runOnModule(Module &M) { if (IGC_GET_FLAG_VALUE(FunctionControl) == FLAG_FCALL_FORCE_INLINE) { return false; } CodeGenContext* ctx = getAnalysis().getCodeGenContext(); m_pMdUtils = getAnalysis().getMetaDataUtils(); CallGraph &CG = getAnalysis().getCallGraph(); if (IGC_IS_FLAG_DISABLED(EnableRecursionOpenCL) && !ctx->m_DriverInfo.AllowRecursion() && hasRecursion(CG)) { assert(0 && "Recursion detected!"); ctx->EmitError(" undefined reference to `jmp()' "); return false; } //Return if any error if (!(ctx->oclErrorMessage.empty())) { return false; } for (auto I = scc_begin(&CG), IE = scc_end(&CG); I != IE; ++I) { const std::vector &SCCNodes = *I; traveseCallGraphSCC(SCCNodes); } return false; } void BuiltinCallGraphAnalysis::traveseCallGraphSCC(const std::vector &SCCNodes) { // all functions in one scc should end up with the same result ImplicitArgmentDetail *argData = nullptr; for (auto CGN : SCCNodes) { Function *f = CGN->getFunction(); if (!f || f->isDeclaration()) continue; // Fail on variadic functions. if (f->isVarArg()) { std::string Msg = "Invalid user defined function being processed: "; Msg += f->getName(); Msg += "()\n"; getAnalysis().getCodeGenContext()->EmitError(Msg.c_str()); return; } if (argData == nullptr) { argDetails.push_back(IGCLLVM::make_unique()); argData = argDetails[argDetails.size() - 1].get(); } // calculate args from sub-routine. // This function have not beeen processed yet, therefore no map-entry for it yet assert(argMap.count(f) == 0); for (auto N : (*CGN)) { Function *sub = N.second->getFunction(); // if callee has not been visited auto argMapIter = argMap.find(sub); // if we have processed the arguments for callee if (argMapIter != argMap.end()) { assert(argMapIter->second); combineTwoArgDetail(*argData, *(argMapIter->second), N.first); } } } for (auto CGN : SCCNodes) { Function *f = CGN->getFunction(); if (!f || f->isDeclaration()) continue; FunctionInfoMetaDataHandle funcInfo = m_pMdUtils->getFunctionsInfoItem(f); // calculate implicit args from function metadata auto I = funcInfo->begin_ImplicitArgInfoList(); auto E = funcInfo->end_ImplicitArgInfoList(); // build everything for (; I != E; I++) { ArgInfoMetaDataHandle argInfo = *I; ImplicitArg::ArgType argId = (ImplicitArg::ArgType)argInfo->getArgId(); if (argId < ImplicitArg::ArgType::STRUCT_START) { // unique implicit argument // if not exit, the following line will add one. ImplicitArg::ArgValSet * setx = &(argData->ArgsMaps[argId]); setx->insert(0); } else if (argId <= ImplicitArg::ArgType::STRUCT_END) { // aggregate implicity argument ImplicitStructArgument info; info.DW0.All.argExplictNum = argInfo->getExplicitArgNum(); info.DW0.All.argOffset = argInfo->getStructArgOffset(); info.DW0.All.argId = argId; (*argData).StructArgSet.insert(info.DW0.Value); } else if (argId <= ImplicitArg::ArgType::IMAGES_END || argId == ImplicitArg::ArgType::GET_OBJECT_ID || argId == ImplicitArg::ArgType::GET_BLOCK_SIMD_SIZE) { // image index, project id int argNum = argInfo->getExplicitArgNum(); ImplicitArg::ArgValSet * setx = &(argData->ArgsMaps[argId]); setx->insert(argNum); } else { // unique implicit argument // if not exit, the following line will add one. ImplicitArg::ArgValSet * setx = &(argData->ArgsMaps[argId]); setx->insert(0); } } } for (auto CGN : SCCNodes) { Function *f = CGN->getFunction(); if (!f || f->isDeclaration()) continue; // write everything back into metaData writeBackAllIntoMetaData(*argData, f); argMap.insert(std::make_pair(f, argData)); } } void BuiltinCallGraphAnalysis::combineTwoArgDetail( ImplicitArgmentDetail &retD, ImplicitArgmentDetail &argD, llvm::Value* v) { for (const auto& argPair : argD.ArgsMaps) { ImplicitArg::ArgType argId = argPair.first; if (argId < ImplicitArg::ArgType::STRUCT_START) { // unique implicit argument // if not exit, the following line will add one. ImplicitArg::ArgValSet * setx = &retD.ArgsMaps[argId]; setx->insert(0); } else if (argId <= ImplicitArg::ArgType::STRUCT_END) { // aggregate implicity argument assert(0 && "wrong location for this kind of argument type"); } else if (argId <= ImplicitArg::ArgType::IMAGES_END || argId == ImplicitArg::ArgType::GET_OBJECT_ID || argId == ImplicitArg::ArgType::GET_BLOCK_SIMD_SIZE) { // image index CallInst *cInst = dyn_cast(v); if (!cInst) { assert(0 && " Not supported"); getAnalysis().getCodeGenContext()->EmitError(" undefined reference to `jmp()' "); return; } ImplicitArg::ArgValSet argSet = argPair.second; ImplicitArg::ArgValSet * setx = &retD.ArgsMaps[argId]; // loop all image arguments on the sub-funtion. for (const auto& argI : argSet) { // find it from calling instruction, and trace it back to parent function argument Value* callArg = CImagesBI::CImagesUtils::traceImageOrSamplerArgument(cInst, argI); Argument* arg = dyn_cast(callArg); if (!arg) { assert(0 && " Not supported"); } setx->insert(arg->getArgNo()); } } else { // unique implicit argument // if not exit, the following line will add one. ImplicitArg::ArgValSet * setx = &retD.ArgsMaps[argId]; setx->insert(0); } } #if defined(_DEBUG) // aggregate structure for (unsigned i = 0; i < argD.StructArgSet.size(); i++) { assert(0 && "wrong argument type in user function"); } #endif } void BuiltinCallGraphAnalysis::writeBackAllIntoMetaData(ImplicitArgmentDetail& data, Function * f) { FunctionInfoMetaDataHandle funcInfo = m_pMdUtils->getFunctionsInfoItem(f); funcInfo->clearImplicitArgInfoList(); for (const auto& A : data.ArgsMaps) { ImplicitArg::ArgType argId = A.first; if (argId < ImplicitArg::ArgType::STRUCT_START) { // unique implicit argument, add it on metadata ArgInfoMetaDataHandle argMD = ArgInfoMetaDataHandle(ArgInfoMetaData::get()); argMD->setArgId(argId); funcInfo->addImplicitArgInfoListItem(argMD); } else if (argId <= ImplicitArg::ArgType::STRUCT_END) { // aggregate implicity argument assert(0 && "wrong location for this kind of argument type"); } else if (argId <= ImplicitArg::ArgType::IMAGES_END || argId == ImplicitArg::ArgType::GET_OBJECT_ID || argId == ImplicitArg::ArgType::GET_BLOCK_SIMD_SIZE) { // image index for (const auto& vOnSet: A.second) { ArgInfoMetaDataHandle argMD = ArgInfoMetaDataHandle(ArgInfoMetaData::get()); argMD->setArgId(argId); argMD->setExplicitArgNum(vOnSet); funcInfo->addImplicitArgInfoListItem(argMD); } } else { // unique implicit argument ArgInfoMetaDataHandle argMD = ArgInfoMetaDataHandle(ArgInfoMetaData::get()); argMD->setArgId(argId); funcInfo->addImplicitArgInfoListItem(argMD); } } for (const auto N : data.StructArgSet) // argument number { ArgInfoMetaDataHandle argMD = ArgInfoMetaDataHandle(ArgInfoMetaData::get()); ImplicitStructArgument info; info.DW0.Value = N; argMD->setExplicitArgNum(info.DW0.All.argExplictNum); argMD->setStructArgOffset(info.DW0.All.argOffset); // offset argMD->setArgId(info.DW0.All.argId); // type funcInfo->addImplicitArgInfoListItem(argMD); } m_pMdUtils->save(f->getParent()->getContext()); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/AddImplicitArgs.hpp000066400000000000000000000137431363533017100261230ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "AdaptorCommon/ImplicitArgs.hpp" #include "Compiler/MetaDataUtilsWrapper.h" #include "common/LLVMWarningsPush.hpp" #include #include #include "common/LLVMWarningsPop.hpp" #include #include namespace IGC { class CodeGenContext; } namespace IGC { class ImplicitArgs; struct ImplicitStructArgument { union _DW0 { struct _All { unsigned int argId : 11; unsigned int argOffset : 11; unsigned int argExplictNum : 10; } All; unsigned int Value; } DW0; }; // struct typedef std::map InfoToImpArgMap; typedef std::map FuncInfoToImpArgMap; typedef std::map ImpArgToExpNum; typedef std::map FuncImpToExpNumMap; /// @brief AddImplicitArgs pass used for changing the function signatures and calls to represent /// the implicit arguments needed by each function and passed from the OpenCL runtime /// This pass depdends on the WIFuncAnalysis pass runing before it /// @Author Marina Yatsina class AddImplicitArgs : public llvm::ModulePass { public: // Pass identification, replacement for typeid static char ID; /// @brief Constructor AddImplicitArgs(); /// @brief Destructor ~AddImplicitArgs() {} /// @brief Provides name of pass virtual llvm::StringRef getPassName() const override { return "AddImplictArgs"; } virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.addRequired(); AU.addRequired(); } /// @brief Main entry point. /// Goes over all functions and changes their signature to contain the implict arguments // needed by each function, goes over all function calls and adds the implicit arguments /// to the function calls /// @param M The destination module. virtual bool runOnModule(llvm::Module &M) override; private: /// @brief Create the type of the new function, /// including all explicit and needed impliict parameters /// @param pFunc The old function /// @param pImplicitArgs The impliict arguments needed by this function /// @returns The new functuin type llvm::FunctionType* getNewFuncType(llvm::Function* pFunc, const ImplicitArgs* pImplicitArgs); /// @brief Transfers uses of old arguments to new arguments, sets names of all arguments /// @param pFunc The old function /// @param pNewFunc The new function /// @param pImplicitArgs The impliict arguments needed by this function void updateNewFuncArgs(llvm::Function* pFunc, llvm::Function* pNewFunc, const ImplicitArgs* pImplicitArgs); // @brief replace old CallInst with new CallInst void replaceAllUsesWithNewOCLBuiltinFunction(CodeGenContext* ctx, llvm::Function* old_func, llvm::Function* new_func); /// @brief Metadata API obejct. IGC::IGCMD::MetaDataUtils *m_pMdUtils; FuncInfoToImpArgMap m_FuncInfoToImpArgMap; FuncImpToExpNumMap m_FuncImpToExpNumMap; }; } // namespace IGC // Builtin CallGraph Analysis Class namespace IGC { struct ImplicitArgmentDetail { ImplicitArg::ArgMap ArgsMaps; std::set StructArgSet; }; class BuiltinCallGraphAnalysis : public llvm::ModulePass { public: static char ID; BuiltinCallGraphAnalysis(); ~BuiltinCallGraphAnalysis() {} virtual llvm::StringRef getPassName() const override { return "BuiltinCallGraphAnalysis"; } void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.addRequired(); AU.addRequired(); AU.addRequired(); } virtual bool runOnModule(llvm::Module &M) override; void traveseCallGraphSCC(const std::vector &SCCNodes); void combineTwoArgDetail(ImplicitArgmentDetail&, ImplicitArgmentDetail&, llvm::Value*); void writeBackAllIntoMetaData(ImplicitArgmentDetail&, llvm::Function*); private: IGC::IGCMD::MetaDataUtils *m_pMdUtils; llvm::SmallDenseMap argMap; llvm::SmallVector, 4> argDetails; }; } // namespace IGC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/IRUpgrader/000077500000000000000000000000001363533017100244065ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/IRUpgrader/IRUpgrader.hpp000066400000000000000000000033451363533017100271300ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ /// Declaration of upgrader passes. When the IR changes, we add passes to keep compatibility with /// clients which haven't moved yet to the new representation. namespace llvm { class Pass; } namespace IGC { /// Transform legacy resource access intrinsics taking an integer representation to /// the new intrinsics taking pointer representation llvm::Pass* CreateUpgradeResourceIntrinsic(); ///Transfor legacy gen intrisics with prefix "@genx." => "@llvm.genx." llvm::Pass* CreateUpgradeGenIntrinsicPrefix(); }intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/IRUpgrader/UpgraderResourceAccess.cpp000066400000000000000000000222651363533017100315240ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "AdaptorCommon/IRUpgrader/IRUpgrader.hpp" #include "GenISAIntrinsics/GenIntrinsics.h" #include "Compiler/CISACodeGen/helper.h" #include #include "common/LLVMWarningsPush.hpp" #include #include #include #include "common/LLVMWarningsPop.hpp" using namespace llvm; class UpgradeResourceAccess : public FunctionPass, public InstVisitor { public: UpgradeResourceAccess() : FunctionPass(ID) {} static char ID; void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.setPreservesCFG(); } bool runOnFunction(llvm::Function &F) override; void visitCallInst(CallInst& C); private: void ChangeIntrinsic(CallInst& C, GenISAIntrinsic::ID ID); void FixSamplerSignature(SampleIntrinsic* sample); bool m_changed = false; }; char UpgradeResourceAccess::ID = 0; bool UpgradeResourceAccess::runOnFunction(llvm::Function &F) { visit(F); return m_changed; } static Value* GetResource(Module* m, IRBuilder<>& builder, Value* i) { unsigned int addrSpace = IGC::EncodeAS4GFXResource(*i, IGC::RESOURCE, 0); PointerType* ptrT = PointerType::get(i->getType(), addrSpace); Value* img = nullptr; if (i->getType() != builder.getInt32Ty()) { // do not make any pointer conversion img = i; } else if(isa(i)) { img = ConstantPointerNull::get(ptrT); } else { Function* getBufferPointer = GenISAIntrinsic::getDeclaration(m, GenISAIntrinsic::GenISA_GetBufferPtr, ptrT); img = builder.CreateCall(getBufferPointer, { i, builder.getInt32(IGC::RESOURCE) }); } return img; } static Value* GetSampler(Module* m, IRBuilder<>& builder, Value* i) { unsigned int addrSpace = IGC::EncodeAS4GFXResource(*i, IGC::SAMPLER, 0); PointerType* ptrT = PointerType::get(i->getType(), addrSpace); Value* s = nullptr; if(isa(i)) { s = ConstantPointerNull::get(ptrT); } else { Function* getBufferPointer = GenISAIntrinsic::getDeclaration(m, GenISAIntrinsic::GenISA_GetBufferPtr, ptrT); s = builder.CreateCall(getBufferPointer, { i, builder.getInt32(IGC::SAMPLER) }); } return s; } void UpgradeResourceAccess::ChangeIntrinsic(CallInst& C, GenISAIntrinsic::ID ID) { std::vector types; std::vector args; IRBuilder<> builder(&C); Module* m = C.getParent()->getParent()->getParent(); for(unsigned int i = 0; i < C.getNumArgOperands(); i++) { args.push_back(C.getOperand(i)); } switch(ID) { case GenISAIntrinsic::GenISA_sampleptr: case GenISAIntrinsic::GenISA_sampleBptr: case GenISAIntrinsic::GenISA_sampleCptr: case GenISAIntrinsic::GenISA_sampleBCptr: case GenISAIntrinsic::GenISA_sampleLptr: case GenISAIntrinsic::GenISA_sampleDptr: case GenISAIntrinsic::GenISA_sampleKillPix: { types.push_back(C.getType()); types.push_back(C.getOperand(0)->getType()); unsigned int resIndex = C.getNumOperands() - 6; unsigned int samplerIndex = C.getNumOperands() - 5; args[resIndex] = GetResource(m, builder, args[resIndex]); args[samplerIndex] = GetSampler(m, builder, args[samplerIndex]); types.push_back(args[resIndex]->getType()); types.push_back(args[samplerIndex]->getType()); } break; case GenISAIntrinsic::GenISA_gather4ptr: { types.push_back(C.getType()); types.push_back(C.getOperand(0)->getType()); unsigned int resIndex = C.getNumOperands() - 7; unsigned int samplerIndex = C.getNumOperands() - 6; args[resIndex] = GetResource(m, builder, args[resIndex]); args[samplerIndex] = GetSampler(m, builder, args[samplerIndex]); types.push_back(args[resIndex]->getType()); types.push_back(args[samplerIndex]->getType()); } break; case GenISAIntrinsic::GenISA_ldmsptr: case GenISAIntrinsic::GenISA_ldptr: { types.push_back(C.getType()); unsigned int resIndex = C.getNumOperands() - 5; args[resIndex] = GetResource(m, builder, args[resIndex]); types.push_back(args[resIndex]->getType()); } break; case GenISAIntrinsic::GenISA_ldmcsptr: { types.push_back(C.getType()); types.push_back(C.getArgOperand(0)->getType()); unsigned int resIndex = C.getNumOperands() - 5; args[resIndex] = GetResource(m, builder, args[resIndex]); types.push_back(args[resIndex]->getType()); } break; default: assert("unhandled intrinsic upgrade" && 0); break; } Function* f = GenISAIntrinsic::getDeclaration(m, ID, types); Value* newCall = builder.CreateCall(f, args); C.replaceAllUsesWith(newCall); C.eraseFromParent(); m_changed = true; } void UpgradeResourceAccess::visitCallInst(CallInst& C) { if (C.isInlineAsm()) { return; } //Check in place for Indirect Calls if(!C.getCalledFunction()) { return; } //Note : This upgrader pass is handling legacy intrinsics as well, // hence we might be dealing with intrinsics starting with @genx. if(C.getCalledFunction()->getName().contains("genx.GenISA.sample.")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_sampleptr); } else if(C.getCalledFunction()->getName().contains("genx.GenISA.sampleB.")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_sampleBptr); } else if(C.getCalledFunction()->getName().contains("genx.GenISA.sampleD.")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_sampleDptr); } else if(C.getCalledFunction()->getName().contains("genx.GenISA.sampleC.")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_sampleCptr); } else if(C.getCalledFunction()->getName().contains("genx.GenISA.sampleL.")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_sampleLptr); } else if(C.getCalledFunction()->getName().contains("genx.GenISA.gather4.")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_gather4ptr); } else if(C.getCalledFunction()->getName().contains("genx.GenISA.ldms.")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_ldmsptr); } else if(C.getCalledFunction()->getName().equals("llvm.genx.GenISA.ldmcs") || C.getCalledFunction()->getName().equals("genx.GenISA.ldmcs")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_ldmcsptr); } else if(C.getCalledFunction()->getName().contains("genx.GenISA.ld.")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_ldptr); } else if(C.getCalledFunction()->getName().contains("genx.GenISA.sampleKill.legacy")) { ChangeIntrinsic(C, GenISAIntrinsic::GenISA_sampleKillPix); } else if(SampleIntrinsic* sample = dyn_cast(&C)) { if(!sample->getTextureValue()->getType()->isPointerTy()) { ChangeIntrinsic(*sample, sample->getIntrinsicID()); } } } class UpgradeGenIntrinsicPrefix : public ModulePass, public InstVisitor { public: UpgradeGenIntrinsicPrefix() : ModulePass(ID) {} static char ID; void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.setPreservesCFG(); } //bool runOnFunction(llvm::Function &F) override; bool runOnModule(llvm::Module &M) override; llvm::StringRef getPassName() const override { return "UpgradeGenIntrinsicPrefix"; } private: bool m_changed = false; }; char UpgradeGenIntrinsicPrefix::ID = 0; bool UpgradeGenIntrinsicPrefix::runOnModule(llvm::Module &M) { for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { Function* pFunc = &(*I); if (pFunc->getName().startswith("genx.")) pFunc->setName("llvm." + pFunc->getName()); } return m_changed; } namespace IGC { Pass* CreateUpgradeResourceIntrinsic() { return new UpgradeResourceAccess(); } Pass* CreateUpgradeGenIntrinsicPrefix() { return new UpgradeGenIntrinsicPrefix(); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/ImplicitArgs.cpp000066400000000000000000000646531363533017100255130ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "ImplicitArgs.hpp" #include "Compiler/Optimizer/OpenCLPasses/KernelArgs.hpp" #include "common/LLVMWarningsPush.hpp" #include #include #include #include #include "common/LLVMWarningsPop.hpp" using namespace llvm; using namespace IGC; using namespace IGC::IGCMD; ImplicitArg::ImplicitArg( const ArgType& argType, const std::string& name, const ValType valType, WIAnalysis::WIDependancy dependency, unsigned int nbElement, ValAlign align, bool isConstantBuf) : m_argType(argType), m_name(name), m_valType(valType), m_dependency(dependency), m_nbElement(nbElement), m_align(align), m_isConstantBuf(isConstantBuf) { } ImplicitArg::ArgType ImplicitArg::getArgType() const { return m_argType; } const std::string& ImplicitArg::getName() const { return m_name; } Type* ImplicitArg::getLLVMType(LLVMContext& context) const { // Return the appropriate LLVM type, based on the argument value type. // This has two quirks: // 1) Pointer size depends on the data layout. // 2) For non-uniform arguments, m_nbElement should be used to determine // the allocation size, but not to determine the LLVM type, because every // work-item sees a scalar. Type* baseType = nullptr; switch(m_valType) { case BYTE: baseType = Type::getInt8Ty(context); break; case SHORT: baseType = Type::getInt16Ty(context); break; case INT: baseType = Type::getInt32Ty(context); break; case LONG: baseType = Type::getInt64Ty(context); break; case FP32: baseType = Type::getFloatTy(context); break; case CONSTPTR: baseType = Type::getInt8Ty(context)->getPointerTo(ADDRESS_SPACE_CONSTANT); break; case PRIVATEPTR: baseType = Type::getInt8Ty(context)->getPointerTo(ADDRESS_SPACE_PRIVATE); break; case GLOBALPTR: baseType = Type::getInt8Ty(context)->getPointerTo(ADDRESS_SPACE_GLOBAL); break; default: assert(0 && "Unrecognized implicit argument type"); return nullptr; } if (m_nbElement == 1 || m_dependency != WIAnalysis::UNIFORM) { return baseType; } else { return VectorType::get(baseType, m_nbElement); } } unsigned int ImplicitArg::getNumberElements() const { return m_nbElement; } VISA_Type ImplicitArg::getVISAType(const DataLayout& DL) const { switch(m_valType) { case BYTE: return VISA_Type::ISA_TYPE_B; break; case SHORT: return VISA_Type::ISA_TYPE_W; break; case INT: return VISA_Type::ISA_TYPE_D; break; case LONG: return VISA_Type::ISA_TYPE_Q; break; case FP32: return VISA_Type::ISA_TYPE_F; break; case CONSTPTR: case GLOBALPTR: case PRIVATEPTR: return getPointerSize(DL) == 4 ? VISA_Type::ISA_TYPE_UD : VISA_Type::ISA_TYPE_UQ; default: assert(0 && "Unrecognized implicit argument type"); } return VISA_Type::ISA_TYPE_UD; } unsigned int ImplicitArg::getPointerSize(const DataLayout& DL) const { switch (m_valType) { case CONSTPTR: return DL.getPointerSize(ADDRESS_SPACE_CONSTANT); case PRIVATEPTR: return DL.getPointerSize(ADDRESS_SPACE_PRIVATE); case GLOBALPTR: return DL.getPointerSize(ADDRESS_SPACE_GLOBAL); default: assert(false && "Unrecognized pointer type"); } return 0; } IGC::e_alignment ImplicitArg::getAlignType(const DataLayout& DL) const { switch (m_align) { case ALIGN_DWORD: return IGC::EALIGN_DWORD; case ALIGN_QWORD: return IGC::EALIGN_QWORD; case ALIGN_GRF: return IGC::EALIGN_GRF; case ALIGN_PTR: return getPointerSize(DL) == 4 ? IGC::EALIGN_DWORD : IGC::EALIGN_QWORD; default: assert(0 && "Uknown alignment"); } return IGC::EALIGN_DWORD; } size_t ImplicitArg::getAlignment(const DataLayout& DL) const { calignmentSize as; return as[getAlignType(DL)]; } WIAnalysis::WIDependancy ImplicitArg::getDependency() const { return m_dependency; } unsigned int ImplicitArg::getAllocateSize(const DataLayout& DL) const { unsigned int elemSize = 0; switch(m_valType) { case BYTE: elemSize = 1; break; case SHORT: elemSize = 2; break; case INT: elemSize = 4; break; case LONG: elemSize = 8; break; case FP32: elemSize = 4; break; case CONSTPTR: case GLOBALPTR: case PRIVATEPTR: elemSize = getPointerSize(DL); break; default: assert(0 && "Unrecognized implicit argument type"); } return m_nbElement * elemSize; } bool ImplicitArg::isConstantBuf() const { return m_isConstantBuf; } bool ImplicitArg::isLocalIDs() const { return (m_argType == ImplicitArg::LOCAL_ID_X || m_argType == ImplicitArg::LOCAL_ID_Y || m_argType == ImplicitArg::LOCAL_ID_Z); } ImplicitArgs::ImplicitArgs(const llvm::Function& func , const MetaDataUtils* pMdUtils) { if (IMPLICIT_ARGS.size() == 0) { IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::R0, "r0", ImplicitArg::INT, WIAnalysis::UNIFORM, 8, ImplicitArg::ALIGN_GRF, false)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::PAYLOAD_HEADER, "payloadHeader", ImplicitArg::INT, WIAnalysis::UNIFORM, 8, ImplicitArg::ALIGN_GRF, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::WORK_DIM, "workDim", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::NUM_GROUPS, "numWorkGroups", ImplicitArg::INT, WIAnalysis::UNIFORM, 3, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::GLOBAL_SIZE, "globalSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 3, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::LOCAL_SIZE, "localSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 3, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::ENQUEUED_LOCAL_WORK_SIZE, "enqueuedLocalSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 3, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::LOCAL_ID_X, "localIdX", ImplicitArg::SHORT, WIAnalysis::RANDOM, 16, ImplicitArg::ALIGN_GRF, false)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::LOCAL_ID_Y, "localIdY", ImplicitArg::SHORT, WIAnalysis::RANDOM, 16, ImplicitArg::ALIGN_GRF, false)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::LOCAL_ID_Z, "localIdZ", ImplicitArg::SHORT, WIAnalysis::RANDOM, 16, ImplicitArg::ALIGN_GRF, false)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::CONSTANT_BASE, "constBase", ImplicitArg::CONSTPTR, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_PTR, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::GLOBAL_BASE, "globalBase", ImplicitArg::GLOBALPTR, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_PTR, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::PRIVATE_BASE, "privateBase", ImplicitArg::PRIVATEPTR, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_PTR, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::PRINTF_BUFFER, "printfBuffer", ImplicitArg::GLOBALPTR, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_PTR, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::BUFFER_OFFSET, "bufferOffset", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::CONSTANT_REG_FP32, "const_reg_fp32", ImplicitArg::FP32, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::CONSTANT_REG_QWORD, "const_reg_qword", ImplicitArg::LONG, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_QWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::CONSTANT_REG_DWORD, "const_reg_dword", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::CONSTANT_REG_WORD, "const_reg_word", ImplicitArg::SHORT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::CONSTANT_REG_BYTE, "const_reg_byte", ImplicitArg::BYTE, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_HEIGHT, "imageHeigt", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_WIDTH, "imageWidth", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_DEPTH, "imageDepth", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_NUM_MIP_LEVELS, "imageNumMipLevels", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_CHANNEL_DATA_TYPE, "imageDataType", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_CHANNEL_ORDER, "imageOrder", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_SRGB_CHANNEL_ORDER, "imageSrgbOrder", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_ARRAY_SIZE, "imageArrSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::IMAGE_NUM_SAMPLES, "imageNumSamples", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::SAMPLER_ADDRESS, "smpAddress", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::SAMPLER_NORMALIZED, "smpNormalized", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::SAMPLER_SNAP_WA, "smpSnapWA", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::FLAT_IMAGE_BASEOFFSET, "flatImageBaseoffset", ImplicitArg::LONG, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_QWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::FLAT_IMAGE_HEIGHT, "flatImageHeight", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::FLAT_IMAGE_WIDTH, "flatImageWidth", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::FLAT_IMAGE_PITCH, "flatImagePitch", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::VME_MB_BLOCK_TYPE, "vmeMbBlockType", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::VME_SUBPIXEL_MODE, "vmeSubpixelMode", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::VME_SAD_ADJUST_MODE, "vmeSadAdjustMode", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::VME_SEARCH_PATH_TYPE, "vmeSearchPathType", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::DEVICE_ENQUEUE_DEFAULT_DEVICE_QUEUE, "deviceEnqueueDefaultDeviceQueue", ImplicitArg::GLOBALPTR, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_PTR, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::DEVICE_ENQUEUE_EVENT_POOL, "deviceEnqueueEventPool", ImplicitArg::GLOBALPTR, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_PTR, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::DEVICE_ENQUEUE_MAX_WORKGROUP_SIZE, "deviceEnqueueMaxWorkgroupSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::DEVICE_ENQUEUE_PARENT_EVENT, "deviceEnqueueParentEvent", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::DEVICE_ENQUEUE_PREFERED_WORKGROUP_MULTIPLE, "deviceEnqueuePreferedWorkgroupMultiple", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::GET_OBJECT_ID, "deviceEnqueueGetObjectId", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::GET_BLOCK_SIMD_SIZE, "deviceEnqueueGetBlockSimdSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::LOCAL_MEMORY_STATELESS_WINDOW_START_ADDRESS, "localMemStatelessWindowStartAddr", ImplicitArg::GLOBALPTR, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_PTR, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::LOCAL_MEMORY_STATELESS_WINDOW_SIZE, "localMemStatelessWindowSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::PRIVATE_MEMORY_STATELESS_SIZE, "PrivateMemStatelessSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_DWORD, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::STAGE_IN_GRID_ORIGIN, "stageInGridOrigin", ImplicitArg::INT, WIAnalysis::UNIFORM, 3, ImplicitArg::ALIGN_GRF, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::STAGE_IN_GRID_SIZE, "stageInGridSize", ImplicitArg::INT, WIAnalysis::UNIFORM, 3, ImplicitArg::ALIGN_GRF, true)); IMPLICIT_ARGS.push_back(ImplicitArg(ImplicitArg::SYNC_BUFFER, "syncBuffer", ImplicitArg::GLOBALPTR, WIAnalysis::UNIFORM, 1, ImplicitArg::ALIGN_PTR, false)); assert(IMPLICIT_ARGS.size() == ImplicitArg::NUM_IMPLICIT_ARGS && "Mismatch in NUM_IMPLICIT_ARGS and IMPLICIT_ARGS vector"); #ifdef _DEBUG // Note: the order that implicit args are added here must match the // order of the ImplicitArg::Argtype enum. Let's check that they match: uint32_t CurArgId = ImplicitArg::START_ID; for (auto &Arg : IMPLICIT_ARGS) { if (Arg.getArgType() != CurArgId++) { assert(0 && "enum and vector out of sync!"); } } #endif // _DEBUG } m_funcInfoMD = pMdUtils->getFunctionsInfoItem(const_cast(&func)); } const ImplicitArg& ImplicitArgs::operator[](unsigned int i) const { assert(IMPLICIT_ARGS.size() == ImplicitArg::NUM_IMPLICIT_ARGS && "Mismatch in NUM_IMPLICIT_ARGS and IMPLICIT_ARGS vector"); return IMPLICIT_ARGS[getArgType(i)]; } unsigned int ImplicitArgs::getArgIndex(ImplicitArg::ArgType argType) { assert(this->size() > 0 && "There are no implicit arguments!"); // Find the first appearance of the given implicit arg type unsigned int implicitArgIndex = 0; for (implicitArgIndex = 0; implicitArgIndex < this->size(); ++implicitArgIndex) { ImplicitArg::ArgType type = getArgType(implicitArgIndex); if (type == argType) { break; } } assert(implicitArgIndex < this->size() && "Implicit argument not found!"); return implicitArgIndex; } bool ImplicitArgs::isImplicitArgExist( const IGCMD::FunctionInfoMetaDataHandle& funcInfo, ImplicitArg::ArgType argType) { bool res = false; if (funcInfo->size_ImplicitArgInfoList() <= 0) //There are no implicit arguments! return res; // Find the first appearance of the given implicit arg type unsigned int implicitArgIndex = 0; for (implicitArgIndex = 0; implicitArgIndex < funcInfo->size_ImplicitArgInfoList(); ++implicitArgIndex) { ImplicitArg::ArgType type = (ImplicitArg::ArgType) funcInfo->getImplicitArgInfoListItem(implicitArgIndex)->getArgId(); if (type == argType) { res = true; break; } } return res; } bool ImplicitArgs::isImplicitArgExist(ImplicitArg::ArgType argType) { return isImplicitArgExist(m_funcInfoMD, argType); } bool ImplicitArgs::isImplicitArgExist( llvm::Function& F, ImplicitArg::ArgType argType, IGCMD::MetaDataUtils* pMdUtils) { return isImplicitArgExist(pMdUtils->getFunctionsInfoItem(&F), argType); } unsigned int ImplicitArgs::getImageArgIndex(ImplicitArg::ArgType argType, const Argument* image) { assert(isImplicitImage(argType) && "Non image/sampler implicit arg!"); return getNumberedArgIndex(argType, image->getArgNo()); } unsigned int ImplicitArgs::getNumberedArgIndex(ImplicitArg::ArgType argType, int argNum) { assert((argNum >= 0) && "objectNum cannot be less than 0"); for (int i = 0, e = m_funcInfoMD->size_ImplicitArgInfoList() ; i < e; ++i) { ArgInfoMetaDataHandle argInfo = m_funcInfoMD->getImplicitArgInfoListItem(i); if (argInfo->getArgId() == argType && argInfo->getExplicitArgNum() == argNum) { return i; } } assert(false && "No implicit argument for the given type & argNum"); return m_funcInfoMD->size_ImplicitArgInfoList(); } void ImplicitArgs::addImplicitArgs(llvm::Function& F, SmallVectorImpl& implicitArgs, MetaDataUtils* pMdUtils) { // Add implicit args metadata for the given function FunctionInfoMetaDataHandle funcInfo = pMdUtils->getFunctionsInfoItem(&F); for (auto arg : implicitArgs) { if (!isImplicitArgExist(F, arg, pMdUtils)) { ArgInfoMetaDataHandle argMD = ArgInfoMetaDataHandle(ArgInfoMetaData::get()); argMD->setArgId(arg); funcInfo->addImplicitArgInfoListItem(argMD); } } pMdUtils->save(F.getParent()->getContext()); } void ImplicitArgs::addImageArgs(llvm::Function& F, ImplicitArg::ArgMap& argMap, MetaDataUtils* pMdUtils) { FunctionInfoMetaDataHandle funcInfo = pMdUtils->getFunctionsInfoItem(&F); for (int i = 0; i < numImageArgTypes; ++i) { ImplicitArg::ArgValSet& argSet = argMap[IndexToArgType.at(i)]; for (const auto& argI : argSet) { ArgInfoMetaDataHandle argMD = ArgInfoMetaDataHandle(ArgInfoMetaData::get()); argMD->setArgId(IndexToArgType.at(i)); argMD->setExplicitArgNum(argI); funcInfo->addImplicitArgInfoListItem(argMD); } } pMdUtils->save(F.getParent()->getContext()); } void ImplicitArgs::addStructArgs(llvm::Function& F, const Argument* A, const ImplicitArg::StructArgList& S, MetaDataUtils* pMdUtils) { FunctionInfoMetaDataHandle funcInfo = pMdUtils->getFunctionsInfoItem(&F); for (auto argI = S.begin(), end = S.end(); argI != end; ++argI) { unsigned int id = argI->first; unsigned int offset = argI->second; ArgInfoMetaDataHandle argMD = ArgInfoMetaDataHandle(ArgInfoMetaData::get()); argMD->setExplicitArgNum(A->getArgNo()); argMD->setArgId(id); argMD->setStructArgOffset(offset); funcInfo->addImplicitArgInfoListItem(argMD); } pMdUtils->save(F.getParent()->getContext()); } void ImplicitArgs::addNumberedArgs(llvm::Function& F, ImplicitArg::ArgMap& argMap, IGCMD::MetaDataUtils* pMdUtils) { FunctionInfoMetaDataHandle funcInfo = pMdUtils->getFunctionsInfoItem(&F); for (const auto& argPair : argMap) { ImplicitArg::ArgType argId = argPair.first; ImplicitArg::ArgValSet argSet = argPair.second; for (const auto& argNum : argSet) { ArgInfoMetaDataHandle argMD = ArgInfoMetaDataHandle(ArgInfoMetaData::get()); argMD->setArgId(argId); argMD->setExplicitArgNum(argNum); funcInfo->addImplicitArgInfoListItem(argMD); } } pMdUtils->save(F.getParent()->getContext()); } // Add one implicit argument for each pointer argument to global or constant buffer. // Note that F is the original input function (ie, without implicit arguments). void ImplicitArgs::addBufferOffsetArgs(llvm::Function& F, IGCMD::MetaDataUtils* pMdUtils, IGC::ModuleMetaData *modMD) { ImplicitArg::ArgMap OffsetArgs; FunctionInfoMetaDataHandle funcInfoMD = pMdUtils->getFunctionsInfoItem(const_cast(&F)); assert(modMD->FuncMD.find(&F) != modMD->FuncMD.end()); FunctionMetaData* funcMD = &modMD->FuncMD.find(&F)->second; for (auto& Arg : F.args() ) { Value* AV = &Arg; PointerType* PTy = dyn_cast(AV->getType()); if (!PTy || (PTy->getPointerAddressSpace() != ADDRESS_SPACE_CONSTANT && PTy->getPointerAddressSpace() != ADDRESS_SPACE_GLOBAL)) { continue; } int argNo = Arg.getArgNo(); std::string argbaseType = ""; if (funcMD->m_OpenCLArgBaseTypes.size() > (unsigned)argNo) argbaseType = funcMD->m_OpenCLArgBaseTypes[argNo]; // Do not generate implicit arg for any image arguments KernelArg::ArgType ImgArgType; if (KernelArg::isImage( &Arg, argbaseType, ImgArgType) || KernelArg::isSampler(&Arg, argbaseType)) { continue; } OffsetArgs[ImplicitArg::BUFFER_OFFSET].insert(argNo); } if (OffsetArgs.size() > 0) { ImplicitArgs::addNumberedArgs(F, OffsetArgs, pMdUtils); } } unsigned int ImplicitArgs::size() const { return m_funcInfoMD->size_ImplicitArgInfoList(); } bool ImplicitArgs::isImplicitImage(ImplicitArg::ArgType argType) { return (argType >= ImplicitArg::IMAGES_START) && (argType <= ImplicitArg::IMAGES_END); } bool ImplicitArgs::isImplicitStruct(ImplicitArg::ArgType argType) { return (argType >= ImplicitArg::STRUCT_START) && (argType <= ImplicitArg::STRUCT_END); } ImplicitArg::ArgType ImplicitArgs::getArgType(unsigned int index) const { assert(index < size() && "Index out of range"); ArgInfoMetaDataHandle argInfo = m_funcInfoMD->getImplicitArgInfoListItem(index); return (ImplicitArg::ArgType)argInfo->getArgId(); } int32_t ImplicitArgs::getExplicitArgNum(unsigned int index) const { ArgInfoMetaDataHandle argInfo = m_funcInfoMD->getImplicitArgInfoListItem(index); if(argInfo->isExplicitArgNumHasValue()) { return argInfo->getExplicitArgNum(); } return -1; } int32_t ImplicitArgs::getStructArgOffset(unsigned int index) const { ArgInfoMetaDataHandle argInfo = m_funcInfoMD->getImplicitArgInfoListItem(index); if (argInfo->isStructArgOffsetHasValue()) { return argInfo->getStructArgOffset(); } return -1; } TODO("Refactor code to avoid code triplication for getArgInFunc(), getImplicitArg() and WIFuncResolution::getImplicitArg()") Argument* ImplicitArgs::getArgInFunc(llvm::Function& F, ImplicitArg::ArgType argType) { assert(IGCLLVM::GetFuncArgSize(F) >= size() && "Invalid number of argumnents in the function!"); unsigned int argIndex = getArgIndex(argType); unsigned int argIndexInFunc = IGCLLVM::GetFuncArgSize(F) - size() + argIndex; Function::arg_iterator arg = F.arg_begin(); for (unsigned int i = 0; i < argIndexInFunc; ++i, ++arg); return &(*arg); } Argument* ImplicitArgs::getImplicitArg(llvm::Function& F, ImplicitArg::ArgType argType) { unsigned int numImplicitArgs = this->size(); if (!isImplicitArgExist(argType)) return nullptr; unsigned int implicitArgIndex = this->getArgIndex(argType); unsigned int implicitArgIndexInFunc = IGCLLVM::GetFuncArgSize(F) - numImplicitArgs + implicitArgIndex; Function::arg_iterator arg = F.arg_begin(); for (unsigned int i = 0; i < implicitArgIndexInFunc; ++i, ++arg); return &(*arg); } Argument* ImplicitArgs::getNumberedImplicitArg(llvm::Function& F, ImplicitArg::ArgType argType, int argNum) { assert(IGCLLVM::GetFuncArgSize(F) >= size() && "Invalid number of arguments in the function!"); unsigned int numImplicitArgs = size(); unsigned int implicitArgIndex = this->getNumberedArgIndex(argType, argNum); if (implicitArgIndex == numImplicitArgs) return nullptr; unsigned int implicitArgIndexInFunc = IGCLLVM::GetFuncArgSize(F) - numImplicitArgs + implicitArgIndex; Function::arg_iterator arg = F.arg_begin(); for (unsigned int i = 0; i < implicitArgIndexInFunc; ++i, ++arg); return &(*arg); } TODO("The allocation size and alignment of constBase should change according to target bitness...") const int ImplicitArgs::numImageArgTypes = ImplicitArg::IMAGES_END - ImplicitArg::IMAGES_START + 1; std::map ImplicitArgs::initIndexToArgMap() { std::map map; for (int i = 0; i < ImplicitArgs::numImageArgTypes; ++i) { map[i] = (ImplicitArg::ArgType)(ImplicitArg::IMAGES_START + i); } return map; } const std::map ImplicitArgs::IndexToArgType = initIndexToArgMap(); intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/ImplicitArgs.hpp000066400000000000000000000372051363533017100255110ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Compiler/CISACodeGen/CISACodeGen.h" #include "Compiler/CISACodeGen/WIAnalysis.hpp" #include "Compiler/MetaDataApi/MetaDataApi.h" #include #include #include #include namespace llvm { class LLVMContext; class Function; class Type; } namespace IGC { /// @brief ImplicitArg is used for representing the implict information that is passed from the /// OpenCL runtime to IGC, charecterize it and allow IGC to use it. /// @Author Marina Yatsina class ImplicitArg { public: /// @brief Type of implicit information passed from the OpenCL runtime enum ArgType { R0, START_ID = R0, PAYLOAD_HEADER, // WI information WORK_DIM, NUM_GROUPS, GLOBAL_SIZE, LOCAL_SIZE, ENQUEUED_LOCAL_WORK_SIZE, LOCAL_ID_X, LOCAL_ID_Y, LOCAL_ID_Z, // Pointer bases and buffers CONSTANT_BASE, GLOBAL_BASE, PRIVATE_BASE, PRINTF_BUFFER, // Buffer offset (for stateless to stateful optim) BUFFER_OFFSET, // Aggregates STRUCT_START, CONSTANT_REG_FP32 = STRUCT_START, CONSTANT_REG_QWORD, CONSTANT_REG_DWORD, CONSTANT_REG_WORD, CONSTANT_REG_BYTE, STRUCT_END = CONSTANT_REG_BYTE, // Images IMAGES_START, IMAGE_HEIGHT = IMAGES_START, IMAGE_WIDTH, IMAGE_DEPTH, IMAGE_NUM_MIP_LEVELS, IMAGE_CHANNEL_DATA_TYPE, IMAGE_CHANNEL_ORDER, IMAGE_SRGB_CHANNEL_ORDER, IMAGE_ARRAY_SIZE, IMAGE_NUM_SAMPLES, SAMPLER_ADDRESS, SAMPLER_NORMALIZED, SAMPLER_SNAP_WA, FLAT_IMAGE_BASEOFFSET, FLAT_IMAGE_HEIGHT, FLAT_IMAGE_WIDTH, FLAT_IMAGE_PITCH, IMAGES_END = FLAT_IMAGE_PITCH, // VME VME_MB_BLOCK_TYPE, VME_SUBPIXEL_MODE, VME_SAD_ADJUST_MODE, VME_SEARCH_PATH_TYPE, // Device Enqueue DEVICE_ENQUEUE_DEFAULT_DEVICE_QUEUE, DEVICE_ENQUEUE_EVENT_POOL, DEVICE_ENQUEUE_MAX_WORKGROUP_SIZE, DEVICE_ENQUEUE_PARENT_EVENT, DEVICE_ENQUEUE_PREFERED_WORKGROUP_MULTIPLE, GET_OBJECT_ID, GET_BLOCK_SIMD_SIZE, // GAS LOCAL_MEMORY_STATELESS_WINDOW_START_ADDRESS, LOCAL_MEMORY_STATELESS_WINDOW_SIZE, PRIVATE_MEMORY_STATELESS_SIZE, STAGE_IN_GRID_ORIGIN, STAGE_IN_GRID_SIZE, SYNC_BUFFER, NUM_IMPLICIT_ARGS }; /// @brief This set type is used to contain function arguments typedef std::set ArgValSet; /// @brief This map type is used to map implicit argument types to /// sets that contain the relevant Values. typedef std::map ArgMap; /// @brief This map type is used to map implicit argument types to // typedef std::pair StructArgElement; typedef std::vector StructArgList; /// @brief LLVM Type enum ValType { BYTE, SHORT, INT, LONG, FP32, CONSTPTR, PRIVATEPTR, GLOBALPTR }; enum ValAlign { ALIGN_QWORD, ALIGN_DWORD, ALIGN_GRF, ALIGN_PTR }; ImplicitArg( const ArgType& argType, const std::string& name, const ValType valType, WIAnalysis::WIDependancy dependency, unsigned int nbElement, ValAlign align, bool isConstantBuf); /// @brief Getter functions ArgType getArgType() const; const std::string& getName() const; llvm::Type* getLLVMType(llvm::LLVMContext& context) const; WIAnalysis::WIDependancy getDependency() const; unsigned int getAllocateSize(const llvm::DataLayout& DL) const; unsigned int getNumberElements() const; VISA_Type getVISAType(const llvm::DataLayout& DL) const; IGC::e_alignment getAlignType(const llvm::DataLayout& DL) const; size_t getAlignment(const llvm::DataLayout& DL) const; unsigned int getPointerSize(const llvm::DataLayout& DL) const; bool isConstantBuf() const; bool isLocalIDs() const; private: ArgType m_argType; std::string m_name; ValType m_valType; WIAnalysis::WIDependancy m_dependency; unsigned int m_nbElement; ValAlign m_align; bool m_isConstantBuf; }; /// @brief ImplicitArgs is used for accessing the actual implict information that is passed from /// the OpenCL runtime to IGC. /// @Author Marina Yatsina class ImplicitArgs { public: // Constructors ImplicitArgs() {} /// @brief Constructor. /// Constructs the function's implicit arguments based on the given function's metadata /// It actually constructs a mapping to a subset of IMPLICIT_ARGS /// @param func the function to get impilcit args for. /// @param the metadata utils object ImplicitArgs(const llvm::Function& func, const IGCMD::MetaDataUtils* pMdUtils); /// @brief Returns the number of implicit arguments that are passed from the runtime /// @return The number of implicit arguments unsigned int size() const; /// @brief Returns the i-th implicit argument /// @param i The implicit argument index /// @return The i-th implicit argument const ImplicitArg& operator[](unsigned int i) const; /// @brief Returns the index of the appropriate implicit argument based on the given argument type /// @param argType The implicit argument type /// @return The implicit argument's index for a given argument type unsigned int getArgIndex(ImplicitArg::ArgType argType); /// @brief Returns the index of the appropriate implicit image or sampler argument /// based on the given argument type and the associated image argument /// @param argType The implicit argument type /// (height/width/depth for images, normalized/address/snapwa for samplers) /// @param image The associated image/sampler argument /// @return The implicit argument's index for a given argument type unsigned int getImageArgIndex(ImplicitArg::ArgType argType, const llvm::Argument* image); /// @brief Returns the index of the appropriate implicit argument /// based on the given argument type and the argument number /// @param argType The implicit argument type /// (height/width/depth for images, normalized/address/snapwa for samplers) /// @param argNum The explicit argument number of the type /// @return The implicit argument's index for a given argument type unsigned int getNumberedArgIndex(ImplicitArg::ArgType argType, int argNum); /// @brief Returns the argument type of the argument at the given index /// @param i The implicit argument index /// @return The argument type of the argument at the given index ImplicitArg::ArgType getArgType(unsigned int i) const; /// @brief Returns the explicit argument number of the given implicit argument index /// @param i The implicit argument index /// @return The explicit argument number of the given implicit argument index int32_t getExplicitArgNum(uint index) const; /// @brief Returns the structure offset of the given implicit argument index /// @param i The implicit argument index /// @return The structure offset of the given implicit argument index int32_t getStructArgOffset(uint index) const; /// @brief Creates implict arguments metadata for the give function based on the given implicit arguments /// it should receive. If implicit metadata exists, it adds to it. /// @param F The function for which to create the implicit argument's metadata /// @param implicitArgs The implicit argument that are required by the given function /// @param pMdUtils The Metadata API object static void addImplicitArgs(llvm::Function& F, llvm::SmallVectorImpl& implicitArgs, IGCMD::MetaDataUtils* pMdUtils); //TODO doc /// @brief Creates implict image arguments metadata for the give function based on the given implicit image /// arguments it should receive. If implicit image metadata exists, it adds to it. /// @param F The function for which to create the implicit argument's metadata /// @param argMap A map of implict argument types to the Value pointers to the arguments /// @param pMdUtils The Metadata API object static void addImageArgs(llvm::Function& F, ImplicitArg::ArgMap& argMap, IGCMD::MetaDataUtils* pMdUtils); // TODO doc static void addStructArgs(llvm::Function& F, const llvm::Argument* A, const ImplicitArg::StructArgList& S, IGCMD::MetaDataUtils* pMdUtils); /// @brief Creates implict arguments metadata for the give function based on the given implicit arguments /// it should receive. If implicit metadata exists, it adds to it. /// @param F The function for which to create the implicit argument's metadata /// @param argMap A map of implict argument types to the set of numbers of arguments /// @param pMdUtils The Metadata API object static void addNumberedArgs(llvm::Function& F, ImplicitArg::ArgMap& argMap, IGCMD::MetaDataUtils* pMdUtils); /// @brief Create implicit arguments metadata for the given function. It adds one /// implicit argument for each explicit pointer argument to global or constant buffer. /// @param F The function for which to create the implicit argument's metadata /// @param pMdUtils The Metadata API object static void addBufferOffsetArgs(llvm::Function& F, IGCMD::MetaDataUtils* pMdUtils, IGC::ModuleMetaData* modMD); /// @brief Returns the (implicit) function argument associated with the given implicit argument type /// @param F The function for which the implict argument should be returned /// @param argType The type of the implict argument that should be returned /// @return The (implicit) function argument associated with the given argument type llvm::Argument* getArgInFunc(llvm::Function& F, ImplicitArg::ArgType argType); /// @brief Check if the given implicit argument type exist in the(implicit) function argument associated /// @param argType The type of the implict argument that should be checked /// @return true if the argument exist, false otherwise. bool isImplicitArgExist(ImplicitArg::ArgType argType); static bool isImplicitArgExist(llvm::Function& F, ImplicitArg::ArgType argType, IGCMD::MetaDataUtils* pMdUtils); /// @brief Returns the (implicit) function argument associated with the given implicit argument type /// @param F The Function for which the implict argument should be returned /// @param argType The type of the implict argument that should be returned /// @return The (implicit) function argument associated with the given argument type /// In case the argument doesn't exist, return nullptr llvm::Argument* getImplicitArg(llvm::Function &F, ImplicitArg::ArgType argType); /// @brief Returns the (implicit) function argument associated with the given implicit argument type /// and argument number /// @param F The Function for which the implict argument should be returned /// @param argType The type of the implict argument that should be returned /// @param argNum The explicit argument number of the type /// @return The (implicit) function argument associated with the given argument type and number /// In case the argument doesn't exist, return nullptr llvm::Argument* getNumberedImplicitArg(llvm::Function &F, ImplicitArg::ArgType argType, int argNum); /// @brief Returns true if the given argument type is an image or sampler. /// @param argType The argument type to check. static bool isImplicitImage(ImplicitArg::ArgType argType); /// @brief Returns true if the given argument type is a struct /// @param argType The argument type to check. static bool isImplicitStruct(ImplicitArg::ArgType argType); private: /// @brief Returns a map between operand numbers in the implicit metadata nodes to /// implicit argument types. static std::map initIndexToArgMap(); private: /// @brief All possible implicit arguments std::vector IMPLICIT_ARGS; /// @brief Maps operand numbers in the implicit argument metadata /// nodes to implicit argument types. static const std::map IndexToArgType; static const int numImageArgTypes; /// @brief The function's metadata information. IGCMD::FunctionInfoMetaDataHandle m_funcInfoMD; static bool isImplicitArgExist( const IGCMD::FunctionInfoMetaDataHandle& funcInfo, ImplicitArg::ArgType argType); }; } // namespace IGC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/ProcessFuncAttributes.cpp000066400000000000000000000445141363533017100274170ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "ProcessFuncAttributes.h" #include "Compiler/MetaDataApi/IGCMetaDataHelper.h" #include "Compiler/MetaDataUtilsWrapper.h" #include "Compiler/IGCPassSupport.h" #include "Compiler/CodeGenPublic.h" #include "Compiler/CodeGenContextWrapper.hpp" #include "SPIRV/SPIRVInternal.h" #include "common/LLVMWarningsPush.hpp" #include "llvmWrapper/IR/Attributes.h" #include #include #include #include #include #include #include #include "common/LLVMWarningsPop.hpp" #include "common/igc_regkeys.hpp" #include #include using namespace llvm; using namespace IGC; using namespace IGC::IGCMD; namespace { class ProcessFuncAttributes : public ModulePass { public: static char ID; virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const { AU.setPreservesCFG(); AU.addRequired(); AU.addRequired(); } ProcessFuncAttributes(); ~ProcessFuncAttributes() {} virtual bool runOnModule(Module &M); virtual llvm::StringRef getPassName() const { return "ProcessFuncAttributes"; } private: bool isGASPointer(Value* arg); }; } // namespace // Register pass to igc-opt #define PASS_FLAG "igc-process-func-attributes" #define PASS_DESCRIPTION "Set Functions' linkage and attributes" #define PASS_CFG_ONLY false #define PASS_ANALYSIS false IGC_INITIALIZE_PASS_BEGIN(ProcessFuncAttributes, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS) IGC_INITIALIZE_PASS_DEPENDENCY(MetaDataUtilsWrapper) IGC_INITIALIZE_PASS_END(ProcessFuncAttributes, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS) char ProcessFuncAttributes::ID = 0; ProcessFuncAttributes::ProcessFuncAttributes() : ModulePass(ID) { initializeProcessFuncAttributesPass(*PassRegistry::getPassRegistry()); } inline bool ProcessFuncAttributes::isGASPointer(Value* V) { if (PointerType *PTy = dyn_cast(V->getType())) { return PTy->getAddressSpace() == ADDRESS_SPACE_GENERIC; } return false; } ModulePass *createProcessFuncAttributesPass() { return new ProcessFuncAttributes(); } extern bool isSupportedAggregateArgument(Argument* arg); // Only pointer, struct and array types are considered. E.g. vector type // cannot contain opaque subtypes, function type may contain but ignored. static void getContainedStructType(Type *T, SmallPtrSetImpl &Tys) { if (StructType *ST = dyn_cast(T)) { // Check if this has been checked, to avoid spinning on %T = { %T *}. if (!Tys.count(ST)) { Tys.insert(ST); for (auto I = ST->element_begin(), E = ST->element_end(); I != E; ++I) { getContainedStructType(*I, Tys); } } } else if (auto PT = dyn_cast(T)) { return getContainedStructType(PT->getElementType(), Tys); } else if (auto AT = dyn_cast(T)) { return getContainedStructType(AT->getElementType(), Tys); } } // Check the existence of an opaque type. static bool containsOpaque(llvm::Type *T) { // All (nested) struct types in T. SmallPtrSet StructTys; getContainedStructType(T, StructTys); for (auto I = StructTys.begin(), E = StructTys.end(); I != E; ++I) { StructType *ST = *I; if (ST->isOpaque()) { return true; } } return false; } // __builtin_spirv related OpGroup call implementations contain both // workgroup and subgroup code in them that is switched on based on the // 'Execution' and 'Operation' parameters and these will almost always // be compile time literals. Let's inline these functions so we have a chance // at optimizing away the branches that contain workgroup code that will cause // SLM allocations when we're really doing a subgroup calls. static DenseSet collectMemPoolUsage(const Module &M) { const char *BUILTIN_MEMPOOL = "__builtin_IB_AllocLocalMemPool"; auto *MemPool = M.getFunction(BUILTIN_MEMPOOL); DenseSet FuncsToInline; if (!MemPool) return FuncsToInline; for (auto *U : MemPool->users()) { if (auto *CI = dyn_cast(U)) { FuncsToInline.insert(CI->getFunction()); } } return FuncsToInline; } bool ProcessFuncAttributes::runOnModule(Module& M) { MetaDataUtilsWrapper &mduw = getAnalysis(); MetaDataUtils *pMdUtils = mduw.getMetaDataUtils(); ModuleMetaData *modMD = mduw.getModuleMetaData(); auto MemPoolFuncs = collectMemPoolUsage(M); CodeGenContext* pCtx = getAnalysis().getCodeGenContext(); std::set fastMathFunct; GlobalVariable *gv_fastMath = M.getGlobalVariable("__FastRelaxedMath", true); if (gv_fastMath) { if (gv_fastMath->getInitializer()->isOneValue()) { // Find the functions which __FastRelaxedMath belongs to.... for (Value::user_iterator U = gv_fastMath->user_begin(), UE = gv_fastMath->user_end(); U != UE; ++U) { Instruction* user = dyn_cast(*U); if (!user) { continue; } fastMathFunct.insert(user->getParent()->getParent()); } } } // lambda for setting indirect function attributes auto SetIndirectFuncAttributes = [this](Function* F)->void { F->addFnAttr("IndirectlyCalled"); F->addFnAttr("visaStackCall"); if (!F->isDeclaration()) { // Require global relocation if any global values are used in indirect functions, since we cannot pass implicit args F->addFnAttr("EnableGlobalRelocation"); if (IGC_GET_FLAG_VALUE(FunctionControl) == FLAG_FCALL_FORCE_INDIRECTCALL) { F->removeFnAttr(llvm::Attribute::AlwaysInline); F->addFnAttr(llvm::Attribute::NoInline); } } }; // 1. Set function's linkage type to InternalLinkage (C's static) so that // LLVM can remove the dead functions asap, which saves compiling time. // Only non-kernel function with function bodies are set. // // 2. For correctness, add AlwaysInline to all functions' attributes so // that AlwaysInliner will inline all of them. bool Changed = false; for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { Function *F = &(*I); if (F->isDeclaration()) { if (F->getName() == "__translate_sampler_initializer") F->addFnAttr(llvm::Attribute::ReadOnly); if (F->hasFnAttribute("referenced-indirectly")) { pCtx->m_enableFunctionPointer = true; SetIndirectFuncAttributes(F); } // It is not a defined function continue; } // If EnableOCLNoInlineAttr is on and F does have // NoInline, do not reset it. if (IGC_IS_FLAG_ENABLED(EnableOCLNoInlineAttr) && pCtx->type == ShaderType::OPENCL_SHADER && F->hasFnAttribute(llvm::Attribute::NoInline) && !F->hasFnAttribute(llvm::Attribute::Builtin)) { continue; } // Do not reset it for critical section builtins if (F->hasFnAttribute("KMPLOCK")) { continue; } // Remove noinline attr if present. F->removeFnAttr(llvm::Attribute::NoInline); if (IGC_IS_FLAG_ENABLED(DisableAddingAlwaysAttribute)) { // Add always attribute if function has an argument with opaque type // Curently, ExtensionArgAnalysis assumes that all functions with image arguments to be inlined // This patch makes sure that we add always inline for such cases for (auto& arg : F->args()) { if (containsOpaque(arg.getType())) { F->addFnAttr(llvm::Attribute::AlwaysInline); break; } } // Add always attribtue if function is a builtin if (F->hasFnAttribute(llvm::Attribute::Builtin)) { F->addFnAttr(llvm::Attribute::AlwaysInline); } } else { // Add AlwaysInline attribute to force inlining all calls. F->addFnAttr(llvm::Attribute::AlwaysInline); } // Go through call sites and remove NoInline atrributes. for (auto I : F->users()) { if (CallInst* callInst = dyn_cast(&*I)) { if (callInst->hasFnAttr(llvm::Attribute::NoInline)) { callInst->removeAttribute(IGCLLVM::AttributeSet::FunctionIndex, llvm::Attribute::NoInline); } } } // set function attributes according to build options so // inliner doesn't conservatively turn off unsafe optimizations // when inlining BIFs (see mergeAttributesForInlining() in inliner). const auto &opts = modMD->compOpt; if (opts.MadEnable) F->addFnAttr("less-precise-fpmad", "true"); if (opts.UnsafeMathOptimizations || opts.FastRelaxedMath) F->addFnAttr("unsafe-fp-math", "true"); if (opts.FiniteMathOnly || opts.FastRelaxedMath) { F->addFnAttr("no-infs-fp-math", "true"); F->addFnAttr("no-nans-fp-math", "true"); } // F is not a kernel // it is builtin, or user function const bool notKernel = pMdUtils->findFunctionsInfoItem(F) == pMdUtils->end_FunctionsInfo(); if (notKernel) { F->setLinkage(GlobalValue::InternalLinkage); Changed = true; } // inline all OCL math functions if __FastRelaxedMath is set if (fastMathFunct.find(F) != fastMathFunct.end()) continue; // The following subroutine check is added to disable two-phase-inlining // when we do not enable subroutines. bool keepAlwaysInline = (MemPoolFuncs.count(F) != 0); if (IGC_GET_FLAG_VALUE(FunctionControl) != FLAG_FCALL_FORCE_INLINE) { if (!keepAlwaysInline) { for (auto &arg : F->args()) { // If argument contains an opaque type e.g. image, then always inline it. // If argument is a pointer to GAS, always inline it for perf reason. // // Note that this workaround should be removed. if (containsOpaque(arg.getType()) || isSupportedAggregateArgument(&arg) || isGASPointer(&arg)) { keepAlwaysInline = true; break; } } // SPIR-V image functions don't contain opaque types for images, // they use i64 values instead. // We need to detect them based on function name. if (F->getName().startswith(spv::kLLVMName::builtinPrefix) && F->getName().contains("Image")) { keepAlwaysInline = true; } } if (!keepAlwaysInline) { F->removeFnAttr(llvm::Attribute::AlwaysInline); } } // Add Optnone to user functions but not on builtins. This allows to run // optimizations on builtins. if (getAnalysis().getModuleMetaData()->compOpt.OptDisable) { if (!F->hasFnAttribute(llvm::Attribute::Builtin)) { F->addFnAttr(llvm::Attribute::OptimizeNone); } } bool istrue = false; if (notKernel || istrue) { if (!keepAlwaysInline) { bool forceSubroutine = IGC_GET_FLAG_VALUE(FunctionControl) == FLAG_FCALL_FORCE_SUBROUTINE; bool forceStackCall = IGC_GET_FLAG_VALUE(FunctionControl) == FLAG_FCALL_FORCE_STACKCALL; if ((forceSubroutine || forceStackCall) && (istrue == false)) { // add the following line in order to stress-test // subroutine call or stack call F->removeFnAttr(llvm::Attribute::AlwaysInline); F->addFnAttr(llvm::Attribute::NoInline); if (forceStackCall) { F->addFnAttr("visaStackCall"); } } } if (IGC_IS_FLAG_ENABLED(EnableFunctionPointer)) { // Check if the function can be called either from // externally or as a function pointer bool isExtern = (F->hasFnAttribute("referenced-indirectly")); bool isIndirect = false; for (auto u = F->user_begin(), e = F->user_end(); u != e; u++) { CallInst* call = dyn_cast(*u); if (!call || call->getCalledValue() != F) { isIndirect = true; } } if (isExtern || isIndirect) { pCtx->m_enableFunctionPointer = true; SetIndirectFuncAttributes(F); if(istrue) F->removeFnAttr("visaStackCall"); if (isExtern) { F->setLinkage(GlobalValue::ExternalLinkage); } } } } Changed = true; } return Changed; } // // ProcessBuiltinMetaData // namespace { class ProcessBuiltinMetaData : public ModulePass { public: static char ID; virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const { AU.setPreservesCFG(); AU.addRequired(); AU.addRequired(); } ProcessBuiltinMetaData(); ~ProcessBuiltinMetaData() {} virtual bool runOnModule(Module &M); virtual llvm::StringRef getPassName() const { return "ProcessBuiltinMetaData"; } private: void updateBuiltinFunctionMetaData(llvm::Function*); MetaDataUtils *m_pMdUtil; }; } // namespace // Register pass to igc-opt #define PASS_FLAG2 "igc-process-builtin-metaData" #define PASS_DESCRIPTION2 "Set builtin MetaData" #define PASS_CFG_ONLY2 false #define PASS_ANALYSIS2 false IGC_INITIALIZE_PASS_BEGIN(ProcessBuiltinMetaData, PASS_FLAG2, PASS_DESCRIPTION2, PASS_CFG_ONLY2, PASS_ANALYSIS2) IGC_INITIALIZE_PASS_DEPENDENCY(MetaDataUtilsWrapper) IGC_INITIALIZE_PASS_DEPENDENCY(CodeGenContextWrapper) IGC_INITIALIZE_PASS_END(ProcessBuiltinMetaData, PASS_FLAG2, PASS_DESCRIPTION2, PASS_CFG_ONLY2, PASS_ANALYSIS2) char ProcessBuiltinMetaData::ID = 0; ProcessBuiltinMetaData::ProcessBuiltinMetaData() : ModulePass(ID) { initializeProcessBuiltinMetaDataPass(*PassRegistry::getPassRegistry()); } ModulePass *createProcessBuiltinMetaDataPass() { return new ProcessBuiltinMetaData(); } bool ProcessBuiltinMetaData::runOnModule(Module& M) { if (IGC_GET_FLAG_VALUE(FunctionControl) == FLAG_FCALL_FORCE_INLINE) { return false; } m_pMdUtil = getAnalysis().getMetaDataUtils(); bool Changed = false; for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { Function *F = &(*I); if (!F || F->isDeclaration()) continue; // add AlwaysInline for functions. It will be handle in optimization phase if (!F->hasFnAttribute(llvm::Attribute::NoInline)) F->addFnAttr(llvm::Attribute::AlwaysInline); // disable JumpThread optimization on the block that contains this function F->setConvergent(); if (m_pMdUtil->findFunctionsInfoItem(F) == m_pMdUtil->end_FunctionsInfo()) { // It is user Function updateBuiltinFunctionMetaData(F); } Changed = true; } return Changed; } void ProcessBuiltinMetaData::updateBuiltinFunctionMetaData(llvm::Function* pFunc) { IGCMD::FunctionInfoMetaDataHandle fHandle = IGCMD::FunctionInfoMetaDataHandle(IGCMD::FunctionInfoMetaData::get()); IGC::ModuleMetaData* modMD = getAnalysis().getCodeGenContext()->getModuleMetaData(); FunctionMetaData *funcMD = &modMD->FuncMD[pFunc]; //okay to insert if not present funcMD->functionType = IGC::FunctionTypeMD::UserFunction; fHandle->setType(FunctionTypeMD::UserFunction); for (auto arg = pFunc->arg_begin(); arg != pFunc->arg_end(); ++arg) { std::string typeStr; llvm::raw_string_ostream x(typeStr); arg->getType()->print(x); funcMD->m_OpenCLArgNames.push_back(arg->getName()); funcMD->m_OpenCLArgAccessQualifiers.push_back("none"); funcMD->m_OpenCLArgBaseTypes.push_back(x.str()); } m_pMdUtil->setFunctionsInfoItem(pFunc, fHandle); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/ProcessFuncAttributes.h000066400000000000000000000025601363533017100270570ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once namespace llvm { class ModulePass; } llvm::ModulePass *createProcessFuncAttributesPass(); llvm::ModulePass *createProcessBuiltinMetaDataPass();intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/TypesLegalizationPass.cpp000066400000000000000000000316331363533017100274120ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "TypesLegalizationPass.hpp" #include "../Compiler/IGCPassSupport.h" using namespace llvm; // Register pass to igc-opt #define PASS_FLAG "types-legalization-pass" #define PASS_DESCRIPTION "Types Legalization pass" #define PASS_CFG_ONLY false #define PASS_ANALYSIS false IGC_INITIALIZE_PASS_BEGIN( TypesLegalizationPass,PASS_FLAG,PASS_DESCRIPTION,PASS_CFG_ONLY,PASS_ANALYSIS ) IGC_INITIALIZE_PASS_END( TypesLegalizationPass,PASS_FLAG,PASS_DESCRIPTION,PASS_CFG_ONLY,PASS_ANALYSIS ) char TypesLegalizationPass::ID = 0; TypesLegalizationPass::TypesLegalizationPass() : FunctionPass( TypesLegalizationPass::ID ) { initializeTypesLegalizationPassPass( *PassRegistry::getPassRegistry() ); } TypesLegalizationPass::TypesLegalizationPass(bool legalizePhi, bool legalizeExtractValue, bool legalizeStore) : FunctionPass( TypesLegalizationPass::ID ), m_LegalizePhi(legalizePhi), m_LegalizeExtractValue(legalizeExtractValue), m_LegalizeStore(legalizeStore) { initializeTypesLegalizationPassPass( *PassRegistry::getPassRegistry() ); } void TypesLegalizationPass::visitExtractValueInst( ExtractValueInst &ev ) { if(m_LegalizeExtractValue) { m_ExtractValueInst.push_back(&ev); } } void TypesLegalizationPass::visitStoreInst( StoreInst &storeInst ) { if(m_LegalizeStore) { Value *arg = storeInst.getOperand( 0 ); if(arg != NULL) { Type *type = arg->getType(); if((type != NULL) && type->isAggregateType()) { m_StoreInst.push_back( &storeInst ); } } } } void TypesLegalizationPass::visitPHINode( PHINode &phi ) { if(m_LegalizePhi) { Type *type = phi.getType(); if((type != NULL) && type->isAggregateType()) { m_PhiNodes.push_back( &phi ); } } } /////////////////////////////////////////////////////////////////////// /// @brief Creates an alloca instruction at the beginning of current /// function /// @param phi instruction to create the alloca for AllocaInst* TypesLegalizationPass::CreateAlloca( Instruction *inst ) { PHINode *phi = dyn_cast(inst); if( phi != NULL) { IRBuilder<> builder( phi ); Function *curFunc = builder.GetInsertBlock()->getParent(); BasicBlock &firstBB = curFunc->getEntryBlock(); BasicBlock::iterator firstInsertPoint = firstBB.getFirstInsertionPt(); builder.SetInsertPoint( &(*firstInsertPoint) ); Type *allocaType = phi->getType(); return builder.CreateAlloca( allocaType ); } else { return NULL; } } /////////////////////////////////////////////////////////////////////// /// @brief Creates GEP instruction. /// @param builder llvm IR builder to use /// @param ptr memory pointer to /// @param indices set of constant indices to use in GEP /// @return Value* - GetElementPtrInst* instruction. Value* TypesLegalizationPass::CreateGEP( IRBuilder<> &builder,Value *ptr,SmallVector &indices ) { SmallVector< Value *,8> gepIndices; gepIndices.reserve( indices.size() + 1 ); gepIndices.push_back( builder.getInt32( 0 ) ); for(unsigned idx : indices) { gepIndices.push_back( builder.getInt32( idx ) ); } return builder.CreateGEP( ptr,gepIndices ); } /////////////////////////////////////////////////////////////////////// /// @brief Resolves a PHI node to alloca store and load. /// @param phi instruction to resolve void TypesLegalizationPass::ResolvePhiNode( PHINode *phi ) { AllocaInst *allocaPtr = TypesLegalizationPass::CreateAlloca( phi ); if(allocaPtr != NULL) { for(unsigned i = 0; i < phi->getNumOperands(); ++i) { IRBuilder<> builder( phi->getIncomingBlock( i )->getTerminator() ); Value* source = phi->getOperand( i ); StoreInst* newStore = builder.CreateStore( source,allocaPtr ); m_StoreInst.push_back( newStore ); } IRBuilder<> builder( phi ); BasicBlock *block = builder.GetInsertBlock(); builder.SetInsertPoint( &(*block->getFirstInsertionPt()) ); Value* newLoad = builder.CreateLoad( allocaPtr ); phi->replaceAllUsesWith( newLoad ); phi->eraseFromParent(); } } /////////////////////////////////////////////////////////////////////// /// @brief Resolves the use of composite types (i.e. structures or /// arrays of vectors) in store and PHI nodes. /// PHI node are resolved to alloca store and loads. Store instructions /// of composite values are resolved to GEP + store of individual /// elements of composite type. bool TypesLegalizationPass::LegalizeTypes() { bool modified = false; // Handle PHI nodes before store instruction as the code creates // new store instructions. for(PHINode *phi : m_PhiNodes) { TypesLegalizationPass::ResolvePhiNode( phi ); modified = true; } for(ExtractValueInst *ev : m_ExtractValueInst) { TypesLegalizationPass::ResolveExtractValue( ev ); modified = true; } for(StoreInst *st : m_StoreInst) { TypesLegalizationPass::ResolveStoreInst( st ); modified = true; } return modified; } /////////////////////////////////////////////////////////////////////// /// @brief Finds a structure field or array element pointed by indices /// @param ip insert point for new instructions /// @param val is a structure or array to extract the elements from /// @param indices specify array element or structure field to get /// @return Value* array element or structure field Value * TypesLegalizationPass::ResolveValue( Instruction *ip,Value *val,SmallVector &indices ) { if(InsertValueInst *civ = dyn_cast(val)) { ArrayRef civIndices = civ->getIndices(); if(indices.size() < civIndices.size()) { // We have less indices collected than it is needed to reference scalar value // inserted here. We will skip this instruction and anticipate there is further // ExtractValue further that will specify missing indices. return nullptr; } unsigned i = 0; for(; i < civIndices.size(); ++i) { if(civIndices[i] != indices[i]) { break; } } if(i == civIndices.size()) { if(i == indices.size()) { return civ->getInsertedValueOperand(); } SmallVector ri( &indices[i],indices.end() ); return ResolveValue( civ,civ->getInsertedValueOperand(),ri ); } return ResolveValue( civ,civ->getAggregateOperand(),indices ); } else if(InsertElementInst* ie = dyn_cast(val)) { IRBuilder<> builder( ie ); assert( indices.size() == 1 ); return builder.CreateExtractElement( ie,builder.getInt32( indices[0] ) ); } else if(LoadInst* ld = dyn_cast(val)) { IRBuilder<> builder( ld ); Value* gep = CreateGEP( builder,ld->getOperand( 0 ),indices ); unsigned alignment = ld->getAlignment(); unsigned pointerTypeSize = gep->getType()->getPointerElementType()->getScalarSizeInBits() / 8; if ( alignment && pointerTypeSize == alignment ) return builder.CreateAlignedLoad( gep, alignment ); return builder.CreateLoad( gep ); } else if(Constant *c = dyn_cast(val)) { IRBuilder<> builder( ip ); // Create ExtractValue - it will be folded. return builder.CreateExtractValue( c,indices ); } else if(ExtractValueInst* ev = dyn_cast(val)) { auto evi = ev->getIndices(); SmallVector newIndices( evi.begin(),evi.end() ); newIndices.append( &indices.front(),&indices.back() ); return ResolveValue( ev,ev->getAggregateOperand(),newIndices ); } else if (auto *II = dyn_cast(val)) { switch (II->getIntrinsicID()) { case Intrinsic::uadd_with_overflow: { // This gets handled in the legalizer. IRBuilder<> builder(ip); return builder.CreateExtractValue(val, indices); } default: break; } } else if ((isa(val) || isa(val)) && val->getType()->isStructTy()) { // Handle struct arguments and structs returned by function calls. IRBuilder<> builder(ip); return builder.CreateExtractValue(val, indices); } else if (PHINode* phi = dyn_cast(val)) { IRBuilder<> builder(&(*ip->getParent()->getFirstInsertionPt())); PHINode* newPhi = builder.CreatePHI(ip->getType(), phi->getNumIncomingValues()); for (unsigned i = 0; i < phi->getNumIncomingValues(); i++) { Value* v = ResolveValue(ip, phi->getIncomingValue(i), indices); newPhi->addIncoming(v, phi->getIncomingBlock(i)); } return newPhi; } else if (SelectInst* select = dyn_cast(val)) { assert(3 == select->getNumOperands()); Value* condition = select->getOperand(0); Value* whenTrue = select->getOperand(1); Value* whenFalse = select->getOperand(2); whenTrue = ResolveValue(select, whenTrue, indices); whenFalse = ResolveValue(select, whenFalse, indices); IRBuilder<> builder(select); return builder.CreateSelect(condition, whenTrue, whenFalse); } // What other kind of instruction can we have here? assert( !"Unresolved instruction!" ); // Fallback by creating an ExtractValueInstr. IRBuilder<> builder( ip ); return builder.CreateExtractValue( val,indices ); } /////////////////////////////////////////////////////////////////////// /// @brief Resolves extract value instructions of composite types into /// sequences of GEP + load /// @param evInst instruction being resolved /// @param type Type* type of current strucuter field or array /// element being resolved /// @param indices leading to current structure filed or array element void TypesLegalizationPass::ResolveExtractValue( ExtractValueInst* evInst ) { IRBuilder<> builder( evInst ); auto evIndices = evInst->getIndices(); SmallVector indices( evIndices.begin(),evIndices.end() ); Value* val = ResolveValue( evInst,evInst->getOperand( 0 ),indices ); if(val) { evInst->replaceAllUsesWith( val ); evInst->eraseFromParent(); } } /////////////////////////////////////////////////////////////////////// /// @brief Resolves store instructions of composite types into /// sequences of GEP + store /// @param storeInst instruction to be resolved /// @param type Type* type of current strucuter field or array /// element being resolved /// @param indices leading to current structure filed or array element void TypesLegalizationPass::ResolveStoreInst( StoreInst *storeInst,Type *type, SmallVector &indices ) { if(type->isStructTy()) { for(unsigned field = 0; field < type->getStructNumElements(); field++) { indices.push_back( field ); ResolveStoreInst( storeInst,type->getStructElementType( field ),indices ); indices.pop_back(); } } else if(type->isArrayTy()) { for(unsigned elem = 0; elem < type->getArrayNumElements(); ++elem) { indices.push_back( elem ); ResolveStoreInst( storeInst,type->getArrayElementType(),indices ); indices.pop_back(); } } else { Value *val = ResolveValue( storeInst,storeInst->getOperand( 0 ),indices ); IRBuilder<> builder( storeInst ); Value *pGEP = CreateGEP( builder,storeInst->getOperand( 1 ),indices ); builder.CreateStore( val,pGEP ); } } /////////////////////////////////////////////////////////////////////// /// @brief Resolves store instructions of composite types into /// sequences of GEP + store /// @param storeInst instruction to be resolved void TypesLegalizationPass::ResolveStoreInst( StoreInst *storeInst ) { SmallVector indices; Value *arg = storeInst->getOperand( 0 ); if(arg != NULL) { ResolveStoreInst( storeInst,arg->getType(),indices ); storeInst->eraseFromParent(); } } bool TypesLegalizationPass::runOnFunction( Function &function ) { this->visit( function ); bool shaderModified = LegalizeTypes(); m_StoreInst.clear(); m_ExtractValueInst.clear(); m_PhiNodes.clear(); return shaderModified; } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/TypesLegalizationPass.hpp000066400000000000000000000055451363533017100274220ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "common/LLVMWarningsPush.hpp" #include #include #include "common/LLVMWarningsPop.hpp" #include "../Compiler/IGCPassSupport.h" class TypesLegalizationPass: public llvm::FunctionPass,public llvm::InstVisitor { public: TypesLegalizationPass(); TypesLegalizationPass(bool legalizePhi, bool legalizeExtractValue, bool legalizeStore); ~TypesLegalizationPass() {} virtual llvm::StringRef getPassName() const override { return "Types Legalization Pass"; } bool LegalizeTypes(); virtual bool runOnFunction(llvm::Function &function) override; void visitStoreInst(llvm::StoreInst &I); void visitExtractValueInst(llvm::ExtractValueInst &I); void visitPHINode(llvm::PHINode &I); void ResolveStoreInst( llvm::StoreInst *st ); void ResolvePhiNode( llvm::PHINode* phi ); void ResolveExtractValue( llvm::ExtractValueInst* extractVal ); void ResolveStoreInst( llvm::StoreInst *st, llvm::Type *ty,llvm::SmallVector &index ); llvm::Value* ResolveValue( llvm::Instruction *st,llvm::Value* arg,llvm::SmallVector &index ); llvm::Value* CreateGEP( llvm::IRBuilder<> &builder,llvm::Value* ptr,llvm::SmallVector &indices ); llvm::AllocaInst* CreateAlloca( llvm::Instruction *phi ); static char ID; llvm::SmallVector m_StoreInst; llvm::SmallVector m_ExtractValueInst; llvm::SmallVector m_PhiNodes; llvm::SmallVector Indicies; protected: bool m_LegalizePhi = true; bool m_LegalizeExtractValue = true; bool m_LegalizeStore = true; }; intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/customApi.cpp000066400000000000000000000506631363533017100250640ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "AdaptorCommon/customApi.hpp" #include #if defined(_WIN32 )|| defined( _WIN64 ) #include "Windows.h" #include #include #include #endif #include "common/debug/Debug.hpp" #include "common/Stats.hpp" #include "common/igc_regkeys.hpp" #include "common/SysUtils.hpp" #include "common/secure_string.h" // strcpy_s() #if defined(IGC_DEBUG_VARIABLES) #include "3d/common/iStdLib/File.h" #endif namespace { #ifndef CL_NUMBER #define CL_NUMBER "" #endif #define _STRINGIFY(x) #x #define STRINGIFY(x) _STRINGIFY(x) #if defined( _DEBUG ) # if defined( _INTERNAL ) # define CONFIGURATION DebugInternal # else # define CONFIGURATION Debug # endif #else # if defined( _INTERNAL ) # define CONFIGURATION ReleaseInternal # else # define CONFIGURATION Release # endif #endif #if defined( _WIN64 ) # define BITWIDTH x64 #elif defined( _WIN32 ) # define BITWIDTH Win32 #else # define BITWIDTH Unknown #endif // We don't want this static string in the RELEASE builds because it can be discovered using the // Windows SysInternals Strings tool. We don't want to leak such information. Unfortunately this // means that RELEASE builds can't be queried for their version information. There is no middle ground. #if defined( _DEBUG ) || defined( _INTERNAL ) static const char g_cBuildInfo[] = "CL: " STRINGIFY(CL_NUMBER) ", " "CONFIGURATION: " STRINGIFY(CONFIGURATION) " " STRINGIFY(BITWIDTH) "\0"; #else static const char g_cBuildInfo[] = "\0"; #endif #undef CONFIGURATION static bool g_debugFlags[ static_cast( IGC::Debug::DebugFlag::END ) ] = {0}; static struct { bool dumpODS; bool dumpFile; } g_dumpFlags[ static_cast( IGC::Debug::DumpType::END ) ] = { }; std::string g_shaderCorpusName; std::string g_shaderOutputFolder; std::string g_shaderOutputName; } namespace IGC { namespace Debug { EnumStr IGC_DEBUG_API_CALL str(DebugFlag value) { #define CASE(x) case DebugFlag::x: return STRINGIFY(x) switch (value) { CASE(DUMPS); CASE(DUMP_AFTER_PASSES); CASE(DUMP_TO_OUTS); CASE(DUMP_TO_OUTPUTDEBUGSTRING); CASE(OPTIMIZATION_STATS); CASE(TIME_STATS_SUM); CASE(TIME_STATS_PER_SHADER); CASE(TIME_STATS_COARSE); CASE(TIME_STATS_PER_PASS); CASE(MEM_STATS); CASE(MEM_STATS_DETAIL); CASE(SHADER_QUALITY_METRICS); CASE(SIMD8_ONLY); CASE(SIMD16_ONLY); CASE(SIMD32_ONLY); CASE(VISA_OUTPUT); CASE(VISA_BINARY); CASE(VISA_DUMPCOMMONISA); CASE(VISA_NOSCHEDULE); CASE(VISA_DOTALL); CASE(VISA_SLOWPATH); CASE(VISA_NOBXMLENCODER); default : assert( 0 && "unknown DebugFlag" ); return ""; } #undef CASE } EnumStr IGC_DEBUG_API_CALL str(DumpType value) { #define CASE(x) case DumpType::x: return STRINGIFY(x) switch (value) { CASE(ASM_TEXT); CASE(ASM_BC); CASE(TRANSLATED_IR_TEXT); CASE(TRANSLATED_IR_BC); CASE(PASS_IR_TEXT); CASE(PASS_IR_BC); CASE(OptIR_TEXT); CASE(OptIR_BC); CASE(VISA_TEXT); CASE(VISA_BC); CASE(GENX_ISA_TEXT); CASE(GENX_ISA_BC); CASE(LLVM_OPT_STAT_TEXT); CASE(TIME_STATS_TEXT); CASE(TIME_STATS_CSV); default : assert( 0 && "unknown DumpType" ); return ""; } #undef CASE } EnumStr IGC_DEBUG_API_CALL str(DumpLoc value) { #define CASE(x) case DumpLoc::x: return STRINGIFY(x) switch (value) { CASE(ODS); CASE(FILE); default : assert( 0 && "unknown DumpLoc" ); return ""; } #undef CASE } void IGC_DEBUG_API_CALL SetCompilerOption(OptionFlag flag, debugString s) { #if defined(IGC_DEBUG_VARIABLES) switch(flag) { #define DECLARE_IGC_REGKEY(dataType, regkeyName, defaultValue, description, releaseMode) \ case OptionFlag::OPTION_##regkeyName: \ strcpy_s(g_RegKeyList.regkeyName.m_string, sizeof(debugString), s); \ break; #include "common/igc_regkeys.def" #undef DECLARE_IGC_REGKEY default: break; } #endif } void IGC_DEBUG_API_CALL SetCompilerOption( OptionFlag flag, int value ) { #if defined(IGC_DEBUG_VARIABLES) switch(flag) { #define DECLARE_IGC_REGKEY(dataType, regkeyName, defaultValue, description, releaseMode) \ case OptionFlag::OPTION_##regkeyName: \ g_RegKeyList.regkeyName.m_Value = value; \ break; #include "common/igc_regkeys.def" #undef DECLARE_IGC_REGKEY default: break; } #endif } extern "C" void IGC_DEBUG_API_CALL SetCompilerOptionValue( const char* flagName, int value ) { #if defined(IGC_DEBUG_VARIABLES) if (!flagName) { return; } SRegKeyVariableMetaData* pRegKeyVariable = (SRegKeyVariableMetaData*)&g_RegKeyList; unsigned NUM_REGKEY_ENTRIES = sizeof(SRegKeysList) / sizeof(SRegKeyVariableMetaData); for (DWORD i = 0; i < NUM_REGKEY_ENTRIES; i++) { const char* name = pRegKeyVariable[i].GetName(); if (!strcmp(flagName, name)) { pRegKeyVariable[i].m_Value = value; break; } } #endif } extern "C" void IGC_DEBUG_API_CALL SetCompilerOptionString( const char* flagName, debugString s ) { #if defined(IGC_DEBUG_VARIABLES) if (!flagName) { return; } SRegKeyVariableMetaData* pRegKeyVariable = (SRegKeyVariableMetaData*)&g_RegKeyList; unsigned NUM_REGKEY_ENTRIES = sizeof(SRegKeysList) / sizeof(SRegKeyVariableMetaData); for (DWORD i = 0; i < NUM_REGKEY_ENTRIES; i++) { const char* name = pRegKeyVariable[i].GetName(); if (!strcmp(flagName, name)) { strcpy_s(pRegKeyVariable[i].m_string,sizeof(debugString), s); break; } } #endif } void IGC_DEBUG_API_CALL SetDebugFlag( DebugFlag flag, bool enabled ) { #if defined( _DEBUG ) || defined( _INTERNAL ) assert( 0 <= static_cast(flag) && static_cast(flag) < static_cast( DebugFlag::END ) && "range sanity check" ); g_debugFlags[ static_cast( flag ) ] = enabled; #else (void) flag; (void) enabled; #endif } bool IGC_DEBUG_API_CALL GetDebugFlag( DebugFlag flag ) { #if defined( _DEBUG ) || defined( _INTERNAL ) #if defined(_WIN32 )|| defined( _WIN64 ) //Disable Dump for OS Applications if ( (DebugFlag::VISA_OUTPUT == flag) || (DebugFlag::VISA_BINARY == flag) || (DebugFlag::VISA_DUMPCOMMONISA == flag) ) { if (GetModuleHandleA("dwm.exe") || GetModuleHandleA("explorer.exe")) { return false; } } #endif assert( 0 <= static_cast(flag) && static_cast(flag) < static_cast( DebugFlag::END ) && "range sanity check" ); return g_debugFlags[ static_cast(flag) ]; #else (void) flag; return false; #endif } void IGC_DEBUG_API_CALL SetDumpFlag( DumpType type, DumpLoc loc, bool enabled ) { #if defined( _DEBUG ) || defined( _INTERNAL ) assert( 0 <= static_cast(type) && static_cast(type) < static_cast( DumpType::END ) && "range sanity check" ); switch (loc) { case DumpLoc::ODS : g_dumpFlags[ static_cast(type) ].dumpODS = enabled; break; case DumpLoc::FILE : g_dumpFlags[ static_cast(type) ].dumpFile = enabled; break; default : assert( 0 && "unreachable" ); break; } #else (void) type; (void) loc; (void) enabled; #endif } bool IGC_DEBUG_API_CALL GetDumpFlag( DumpType type, DumpLoc loc ) { #if defined( _DEBUG ) || defined( _INTERNAL ) assert( 0 <= static_cast(type) && static_cast(type) < static_cast( DumpType::END ) && "range sanity check" ); #if defined(_WIN32 )|| defined( _WIN64 ) //Disable Dump for OS Applications if (GetModuleHandleA("dwm.exe") || GetModuleHandleA("explorer.exe")) { return false; } #endif switch (loc) { case DumpLoc::ODS : return g_dumpFlags[ static_cast(type) ].dumpODS; case DumpLoc::FILE : return g_dumpFlags[ static_cast(type) ].dumpFile; default : assert( 0 && "unreachable" ); return false; } #else (void) type; (void) loc; return false; #endif } void IGC_DEBUG_API_CALL SetShaderCorpusName( CorpusName name ) { #if defined( _DEBUG ) || defined( _INTERNAL ) g_shaderCorpusName = name; #else (void) name; #endif } CorpusName IGC_DEBUG_API_CALL GetShaderCorpusName() { #if defined( _DEBUG ) || defined( _INTERNAL ) return g_shaderCorpusName.c_str(); #else return ""; #endif } void IGC_DEBUG_API_CALL SetShaderOutputFolder( OutputFolderName name ) { #if defined(IGC_DEBUG_VARIABLES) g_shaderOutputFolder = name; #endif } void IGC_DEBUG_API_CALL SetShaderOutputName( OutputName name ) { #if defined(IGC_DEBUG_VARIABLES) g_shaderOutputName = name; #endif } OutputFolderName IGC_DEBUG_API_CALL GetBaseIGCOutputFolder() { #if defined(IGC_DEBUG_VARIABLES) static std::mutex m; std::lock_guard lck(m); static std::string IGCBaseFolder; if(IGCBaseFolder != "") { return IGCBaseFolder.c_str(); } # if defined(_WIN64) || defined(_WIN32) if (!IGC_IS_FLAG_ENABLED(DumpToCurrentDir) && !IGC_IS_FLAG_ENABLED(DumpToCustomDir)) { bool needMkdir = IGC_IS_FLAG_ENABLED(DumpLLVMIR) || IGC_IS_FLAG_ENABLED(EnableCosDump) || IGC_IS_FLAG_ENABLED(EnableVISAOutput) || IGC_IS_FLAG_ENABLED(EnableVISABinary) || IGC_IS_FLAG_ENABLED(EnableVISADumpCommonISA) || GetDebugFlag(DebugFlag::DUMP_AFTER_PASSES) || GetDebugFlag(DebugFlag::VISA_OUTPUT) || GetDebugFlag(DebugFlag::VISA_BINARY) || GetDebugFlag(DebugFlag::VISA_DUMPCOMMONISA) || IGC_IS_FLAG_ENABLED(EnableCapsDump) || IGC_IS_FLAG_ENABLED(ShaderOverride); char dumpPath[256]; sprintf_s(dumpPath, "c:\\Intel\\IGC\\"); if(GetFileAttributesA(dumpPath) != FILE_ATTRIBUTE_DIRECTORY && needMkdir) { _mkdir(dumpPath); } // Make sure we can write in the dump folder as the app may be sandboxed if(needMkdir) { int tmp_id = _getpid(); std::string testFilename = std::string(dumpPath) + "testfile" + std::to_string(tmp_id); HANDLE testFile = CreateFileA(testFilename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); if(testFile == INVALID_HANDLE_VALUE) { char temppath[256]; if(GetTempPathA(sizeof(temppath), temppath) != 0) { sprintf_s(dumpPath, "%sIGC\\", temppath); } } else { CloseHandle(testFile); } } if(GetFileAttributesA(dumpPath) != FILE_ATTRIBUTE_DIRECTORY && needMkdir) { _mkdir(dumpPath); } IGCBaseFolder = dumpPath; } else if (IGC_IS_FLAG_ENABLED(DumpToCustomDir)) { std::string dumpPath = "c:\\Intel\\IGC\\"; // default if something goes wrong const char* custom_dir = IGC_GET_REGKEYSTRING(DumpToCustomDir); if (custom_dir != nullptr && strlen(custom_dir) > 0) { dumpPath = custom_dir; } char pathBuf[256]; iSTD::CreateAppOutputDir(pathBuf, 256, dumpPath.c_str(), false, false, false); IGCBaseFolder = pathBuf; } #elif defined ANDROID if(IGC_IS_FLAG_ENABLED(DumpToCurrentDir)) return ""; IGCBaseFolder = "/sdcard/intel/igc/"; #elif defined __linux__ if (!IGC_IS_FLAG_ENABLED(DumpToCustomDir)) { IGCBaseFolder = "/tmp/IntelIGC/"; } else { std::string dumpPath = "/tmp/IntelIGC/"; // default if something goes wrong const char* custom_dir = IGC_GET_REGKEYSTRING(DumpToCustomDir); if (custom_dir != nullptr && strlen(custom_dir) > 0) { dumpPath = custom_dir; } char pathBuf[256]; iSTD::CreateAppOutputDir(pathBuf, 256, dumpPath.c_str(), false, false, false); IGCBaseFolder = pathBuf; } #endif return IGCBaseFolder.c_str(); #else return ""; #endif } OutputFolderName IGC_DEBUG_API_CALL GetShaderOverridePath() { if(IGC_IS_FLAG_ENABLED(ShaderOverride)) { static std::mutex m; std::lock_guard lck(m); static std::string overridePath; if(overridePath == "") { overridePath = std::string(GetBaseIGCOutputFolder()) + "ShaderOverride/"; } return overridePath.c_str(); } return ""; } OutputFolderName IGC_DEBUG_API_CALL GetShaderOutputFolder() { #if defined(IGC_DEBUG_VARIABLES) static std::mutex m; std::lock_guard lck(m); if(g_shaderOutputFolder != "") { return g_shaderOutputFolder.c_str(); } # if defined(_WIN64) || defined(_WIN32) if (!IGC_IS_FLAG_ENABLED(DumpToCurrentDir) && !IGC_IS_FLAG_ENABLED(DumpToCustomDir)) { char dumpPath[256]; sprintf_s(dumpPath, "%s", GetBaseIGCOutputFolder()); char appPath[MAX_PATH] = { 0 }; // check a process id and make an adequate directory for it: if (::GetModuleFileNameA(NULL, appPath, sizeof(appPath)-1)) { std::string appPathStr = std::string(appPath); int pos = appPathStr.find_last_of("\\") + 1; if (IGC_IS_FLAG_ENABLED(ShaderDumpPidDisable)) { sprintf_s(dumpPath, "%s%s\\", dumpPath, appPathStr.substr(pos, MAX_PATH).c_str()); } else { sprintf_s(dumpPath, "%s%s_%d\\", dumpPath, appPathStr.substr(pos, MAX_PATH).c_str(), _getpid()); } } else { sprintf_s(dumpPath, "%sunknownProcess_%d\\", dumpPath, _getpid()); } if (GetFileAttributesA(dumpPath) != FILE_ATTRIBUTE_DIRECTORY) { _mkdir(dumpPath); } g_shaderOutputFolder = dumpPath; } else if (IGC_IS_FLAG_ENABLED(DumpToCustomDir)) { char pathBuf[256]; iSTD::CreateAppOutputDir(pathBuf, 256, GetBaseIGCOutputFolder(), false, true, !IGC_IS_FLAG_ENABLED(ShaderDumpPidDisable)); g_shaderOutputFolder = pathBuf; } #elif defined ANDROID if (IGC_IS_FLAG_ENABLED(DumpToCurrentDir)) return ""; if (!SysUtils::CreateDir(GetBaseIGCOutputFolder(), true, IGC_IS_FLAG_DISABLED(ShaderDumpPidDisable), &g_shaderOutputFolder)) g_shaderOutputFolder = ""; #elif defined __linux__ if (!IGC_IS_FLAG_ENABLED(DumpToCurrentDir) && g_shaderOutputFolder == "" && !IGC_IS_FLAG_ENABLED(DumpToCustomDir)) { bool needMkdir = false; if (IGC_IS_FLAG_ENABLED(DumpLLVMIR) || IGC_IS_FLAG_ENABLED(EnableCosDump) || IGC_IS_FLAG_ENABLED(EnableVISAOutput) || IGC_IS_FLAG_ENABLED(EnableVISABinary) || IGC_IS_FLAG_ENABLED(EnableVISADumpCommonISA) || GetDebugFlag(DebugFlag::DUMP_AFTER_PASSES) || GetDebugFlag(DebugFlag::VISA_OUTPUT) || GetDebugFlag(DebugFlag::VISA_BINARY) || GetDebugFlag(DebugFlag::VISA_DUMPCOMMONISA) || IGC_IS_FLAG_ENABLED(EnableCapsDump)) { needMkdir = true; } char path[MAX_PATH] = { 0 }; bool pidEnabled = IGC_IS_FLAG_ENABLED(ShaderDumpPidDisable); if (needMkdir) { iSTD::CreateAppOutputDir( path, MAX_PATH, GetBaseIGCOutputFolder(), false, true, pidEnabled); } g_shaderOutputFolder = path; } else if (IGC_IS_FLAG_ENABLED(DumpToCustomDir)) { char pathBuf[256]; iSTD::CreateAppOutputDir(pathBuf, 256, GetBaseIGCOutputFolder(), false, false, false); g_shaderOutputFolder = pathBuf; } #endif return g_shaderOutputFolder.c_str(); #else return ""; #endif } OutputName IGC_DEBUG_API_CALL GetShaderOutputName() { #if defined(IGC_DEBUG_VARIABLES) return g_shaderOutputName.c_str(); #else return ""; #endif } VersionInfo IGC_DEBUG_API_CALL GetVersionInfo() { return g_cBuildInfo; } } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorCommon/customApi.hpp000066400000000000000000000300161363533017100250570ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "usc.h" #include "common/igc_regkeys.hpp" #if !( defined( IGC_EXPORTS ) || defined( _DEBUG ) || defined( _INTERNAL ) ) # include #endif // In _RELEASE builds, make these api functions available for internal use, // but do not export them in the dll. #if defined( _DEBUG ) || defined( _INTERNAL ) # if defined( _WIN32 ) # if defined( IGC_EXPORTS ) # define IGC_DEBUG_API_CALL __declspec(dllexport) # else # define IGC_DEBUG_API_CALL __declspec(dllimport) # endif # else # if defined( IGC_EXPORTS ) # define IGC_DEBUG_API_CALL __attribute__((visibility("default"))) # else # define IGC_DEBUG_API_CALL # endif # endif #else # define IGC_DEBUG_API_CALL #endif namespace IGC { namespace Debug { /// enum to set the compiler flags from the custom API enum class OptionFlag { #define DECLARE_IGC_REGKEY(dataType, regkeyName, defaultValue, description, releaseMode) \ OPTION_##regkeyName, #include "common/igc_regkeys.def" #undef DECLARE_IGC_REGKEY END, BEGIN = 0 }; /// Enumeration of flags for debugging various internal states of the compiler. enum class DebugFlag { DUMPS, //!< Dumps of dxasm, llvm-ir, cisa, isa to ods() and files DUMP_AFTER_PASSES, //!< Controls whether llvm-ir is dumped after passes DUMP_TO_OUTS, //!< Controls whether text streamed into IGC::ods() should go to llvm::outs() DUMP_TO_OUTPUTDEBUGSTRING, //!< Controls whether text streamed into IGC::ods() should go to OutputDebugString OPTIMIZATION_STATS, //!< Timing of various compiler optimizations TIME_STATS_SUM, //!< Timing of translation, code generation, finalizer, etc TIME_STATS_PER_SHADER, //!< Like TIME_STATS_SUM, but one stat measurement per shader (instead of summed up times) TIME_STATS_COARSE, //!< Only collect/dump coarse level time stats, i.e. skip opt detail timer for now > TIME_STATS_PER_PASS, //!< Collect Timing of IGC/LLVM passes MEM_STATS, //!< Measurements related to allocations and deallocations MEM_STATS_DETAIL, //!< dump detail memstats SHADER_QUALITY_METRICS, //!< ISA quality measurements (i.e. count of instructions generated) SIMD8_ONLY, //!< only compile SIMD8 SIMD16_ONLY, //!< only compile SIMD16 SIMD32_ONLY, //!< only compile SIMD32 VISA_OUTPUT, //!< dump gen isa text format from vISA VISA_BINARY, //!< dump gen isa binary format from vISA VISA_DUMPCOMMONISA, //!< dump vISA shaders VISA_NOSCHEDULE, //!< skip instruction scheduling in vISA VISA_DOTALL, //!< dump vISA details VISA_SLOWPATH, VISA_NOBXMLENCODER, //!< do not perform binary encoding using BXML based encoder, but fall-back to old proven encoder NO_ASM_LINE_NO_DUMP_IN_FILE, //!< Do not dump asm line numbers in file. END, BEGIN = 0 }; /// Enumeration of flags for determining which states to dump enum class DumpType { NOS_TEXT, //!< Non-orthogonal states (numan readable) CIS_TEXT, //!< Compiler input structure (human readable) COS_TEXT, //!< Compiler output structure (human readable) ASM_TEXT, //!< Input assembly (human readable) ASM_BC, //!< Input assembly (bitcode) TRANSLATED_IR_TEXT, //!< Translated llvm IR (human readable) TRANSLATED_IR_BC, //!< Translated llvm IR (bitcode) PASS_IR_TEXT, //!< llvm-IR during the optimization passes (human readable) PASS_IR_BC, //!< llvm-IR during the optimization passes (bitcode) OptIR_TEXT, //!< Optimized llvm IR (human readable) OptIR_BC, //!< Optimized llvm IR (bitcode) VISA_TEXT, //!< Virtual-ISA (human readable) VISA_BC, //!< Virtual-ISA (bitcode) GENX_ISA_TEXT, //!< Target ISA (human readable) GENX_ISA_BC, //!< Target ISA (bitcode) LLVM_OPT_STAT_TEXT, //!< llvm optimization stats (human readable) TIME_STATS_TEXT, //!< Time stats (human readable) TIME_STATS_CSV, //!< Time stats (csv, machine readable text) DBG_MSG_TEXT, //!< Debug message END, BEGIN = 0 }; /// Enumeration of the locations to dump to enum class DumpLoc { ODS, //!< Dump to Terminal, as well as OutputDebugString FILE, //!< Dump to an appropriately named file }; /// \brief Version information for this particular build. /// /// This is how a build identifies itself. This type is to be something that is /// streamable into std::ostream's and llvm::raw_ostream's. For now this means its a char*. typedef const char* VersionInfo; /// String representation of an enum typedef const char* EnumStr; /// String representation of a corpus name typedef const char* CorpusName; /// String representation of a output folder name typedef const char* OutputFolderName; typedef const char* OutputName; #if defined( IGC_EXPORTS ) || defined( _DEBUG ) || defined( _INTERNAL ) /// Convert enum value to string EnumStr IGC_DEBUG_API_CALL str(DebugFlag value); /// Convert enum value to string EnumStr IGC_DEBUG_API_CALL str(DumpType value); /// Convert enum value to string EnumStr IGC_DEBUG_API_CALL str(DumpLoc value); /// Convert string to enum value template TEnum enumFrom(EnumStr valueStr) { for (int i = static_cast(TEnum::BEGIN); i < static_cast(TEnum::END); ++i) { if ( strcmp( str( static_cast(i) ), valueStr ) ) { return static_cast(i); } } return TEnum::END; } // Handle both bool and int using the same function. For boolean, // true is converted to int 1 and false is converted to int 0. void IGC_DEBUG_API_CALL SetCompilerOption(OptionFlag flag, int value); void IGC_DEBUG_API_CALL SetCompilerOption(OptionFlag flag, debugString s); extern "C" void IGC_DEBUG_API_CALL SetCompilerOptionValue(const char* flagName, int value); extern "C" void IGC_DEBUG_API_CALL SetCompilerOptionString(const char* flagName, debugString s); /// Assign the state of a debug flag (for _DEBUG and _INTERNAL builds only) void IGC_DEBUG_API_CALL SetDebugFlag( DebugFlag flag, bool enabled ); /// Query the state of a debug flag (for _DEBUG and _INTERNAL builds only) bool IGC_DEBUG_API_CALL GetDebugFlag( DebugFlag flag ); /// Assign the state of a dump flag (for _DEBUG and _INTERNAL builds only) void IGC_DEBUG_API_CALL SetDumpFlag( DumpType type, DumpLoc loc, bool enabled ); /// Query the state of a dump flag (for )DEBUG and _INTERNAL builds only) bool IGC_DEBUG_API_CALL GetDumpFlag( DumpType type, DumpLoc loc); /// Set a name for the to-be-compiled set of shaders void IGC_DEBUG_API_CALL SetShaderCorpusName( CorpusName name ); /// Get the name for the to-be-compiled set of shaders CorpusName IGC_DEBUG_API_CALL GetShaderCorpusName(); /// Set a name for the output folder void IGC_DEBUG_API_CALL SetShaderOutputFolder( OutputFolderName name ); void IGC_DEBUG_API_CALL SetShaderOutputName( OutputName name ); OutputFolderName IGC_DEBUG_API_CALL GetShaderOverridePath(); /// Get the name for the output folder OutputFolderName IGC_DEBUG_API_CALL GetShaderOutputFolder(); OutputName IGC_DEBUG_API_CALL GetShaderOutputName(); /// Ask the build to identify itself VersionInfo IGC_DEBUG_API_CALL GetVersionInfo(); #else // These stubs are for IGCStandalone's includes in _RELEASE builds // This makes it so that we don't have to #ifdef around all of the uses /// Returns END in _RELEASE builds template TEnum enumFrom(const char* str) { return TEnum::END; } /// Returns empty string in _RELEASE builds inline const char* str(DebugFlag value) { (void) value; return ""; } /// Returns empty string in _RELEASE builds inline const char* str(DumpType value) { (void) value; return ""; } /// Returns empty string in _RELEASE builds inline const char* str(DumpLoc value) { (void) value; return ""; } /// Do nothing in _RELEASE builds inline void SetDebugFlag( DebugFlag flag, bool enabled ) { if ( enabled ) { printf("WARNING: Debug flags have no effect in _RELEASE builds\n"); } } /// Returns false in _RELEASE builds inline bool GetDebugFlag( DebugFlag flag ) { return false; } /// Assign the state of a dump flag (for _DEBUG and _INTERNAL builds only) inline void SetDumpFlag( DumpType type, DumpLoc loc, bool enabled ) { } /// Returns false in _RELEASE builds inline bool GetDumpFlag( DumpType type, DumpLoc loc) { return false; } /// Does nothing in _RELEASE builds inline void IGC_DEBUG_API_CALL SetShaderCorpusName( CorpusName name ) { } /// Returns empty string in _RELEASE builds inline CorpusName IGC_DEBUG_API_CALL GetShaderCorpusName() { return ""; } /// Does nothing in _RELEASE builds inline void IGC_DEBUG_API_CALL SetShaderOutputFolder( OutputFolderName name ) { } inline void IGC_DEBUG_API_CALL SetShaderOutputName( OutputName name ) { } /// Returns empty string in _RELEASE builds inline OutputFolderName IGC_DEBUG_API_CALL GetShaderOutputFolder() { return ""; } inline OutputName IGC_DEBUG_API_CALL GetShaderOutputName() { return ""; } /// Omits changelist and build number in _RELEASE builds inline VersionInfo GetVersionInfo() { return "CONFIGURATION: Release"; } #endif } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/000077500000000000000000000000001363533017100215675ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/CLElfLib/000077500000000000000000000000001363533017100231435ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/CLElfLib/CLElfTypes.h000066400000000000000000000221111363533017100252630ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ /*****************************************************************************\ Abstract: Defines the types used for ELF headers/sections. This uses System V Application Binary Interface - DRAFT - 19 October 2010 as a reference as well as LLVM's ELF.h to ensure compatibility. \******************************************************************************/ #pragma once #if defined(__linux__) && defined(OGL) #include "os_inc.h" #endif #if !defined(_MSC_VER) // || (_MSC_VER >= 1700) // NOTE: This header will most likely be supported in MSVC 2012 #include #endif #if defined(__linux__) #include "elf.h" #endif #include namespace CLElfLib { /******************************************************************************\ ELF Enumerates \******************************************************************************/ // E_RETVAL - return values used by ELF access/read/write helper functions enum E_RETVAL { SUCCESS = 0, FAILURE = 1, OUT_OF_MEMORY = 2, }; // E_ID_IDX - Defines a file as being ELF enum E_ID_IDX { ID_IDX_MAGIC0 = 0, ID_IDX_MAGIC1 = 1, ID_IDX_MAGIC2 = 2, ID_IDX_MAGIC3 = 3, ID_IDX_CLASS = 4, ID_IDX_VERSION = 5, ID_IDX_OSABI = 6, ID_IDX_ABI_VERSION = 7, ID_IDX_PADDING = 8, ID_IDX_NUM_BYTES = 16, }; // E_EHT_CLASS - Describes what data types the ELF structures will use. enum E_EH_CLASS { EH_CLASS_NONE = 0, EH_CLASS_32 = 1, // Use Elf32 data types EH_CLASS_64 = 2, // Use Elf64 data types }; // E_EHT_TYPE - List of pre-defined types header types. // OS-specific codes start at 0xfe00 and run to 0xfeff. // Processor-specific codes start at 0xff00 and end at 0xffff. enum E_EH_TYPE { EH_TYPE_NONE = 0, EH_TYPE_RELOCATABLE = 1, EH_TYPE_EXECUTABLE = 2, EH_TYPE_DYNAMIC = 3, EH_TYPE_CORE = 4, EH_TYPE_OPENCL_SOURCE = 0xff01, // format used to pass CL text sections to FE EH_TYPE_OPENCL_OBJECTS = 0xff02, // format used to pass LLVM objects / store LLVM binary output EH_TYPE_OPENCL_LIBRARY = 0xff03, // format used to store LLVM archive output EH_TYPE_OPENCL_EXECUTABLE = 0xff04, // format used to store executable output EH_TYPE_OPENCL_DEBUG = 0xff05, // format used to store debug output }; // E_EH_MACHINE - List of pre-defined machine types. // For OpenCL, currently, we do not need this information, so this is not // fully defined. enum E_EH_MACHINE { EH_MACHINE_NONE = 0, //EHT_MACHINE_LO_RSVD = 1, // Beginning of range of reserved types. //EHT_MACHINE_HI_RSVD = 200, // End of range of reserved types. }; // E_EHT_VERSION - ELF header version options. enum E_EHT_VERSION { EH_VERSION_INVALID = 0, EH_VERSION_CURRENT = 1, }; // E_SH_TYPE - List of pre-defined section header types. // Processor-specific codes start at 0xff00 and end at 0xffff. enum E_SH_TYPE { SH_TYPE_NULL = 0, SH_TYPE_PROG_BITS = 1, SH_TYPE_SYM_TBL = 2, SH_TYPE_STR_TBL = 3, SH_TYPE_RELO_ADDS = 4, SH_TYPE_HASH = 5, SH_TYPE_DYN = 6, SH_TYPE_NOTE = 7, SH_TYPE_NOBITS = 8, SH_TYPE_RELO_NO_ADDS = 9, SH_TYPE_SHLIB = 10, SH_TYPE_DYN_SYM_TBL = 11, SH_TYPE_INIT = 14, SH_TYPE_FINI = 15, SH_TYPE_PRE_INIT = 16, SH_TYPE_GROUP = 17, SH_TYPE_SYMTBL_SHNDX = 18, SH_TYPE_OPENCL_SOURCE = 0xff000000, // CL source to link into LLVM binary SH_TYPE_OPENCL_HEADER = 0xff000001, // CL header to link into LLVM binary SH_TYPE_OPENCL_LLVM_TEXT = 0xff000002, // LLVM text SH_TYPE_OPENCL_LLVM_BINARY = 0xff000003, // LLVM byte code SH_TYPE_OPENCL_LLVM_ARCHIVE = 0xff000004, // LLVM archives(s) SH_TYPE_OPENCL_DEV_BINARY = 0xff000005, // Device binary (coherent by default) SH_TYPE_OPENCL_OPTIONS = 0xff000006, // CL Options SH_TYPE_OPENCL_PCH = 0xff000007, // PCH (pre-compiled headers) SH_TYPE_OPENCL_DEV_DEBUG = 0xff000008, // Device debug SH_TYPE_SPIRV = 0xff000009, // SPIRV SH_TYPE_NON_COHERENT_DEV_BINARY = 0xff00000a, // Non-coherent Device binary SH_TYPE_SPIRV_SC_IDS = 0xff00000b, // Specialization Constants IDs SH_TYPE_SPIRV_SC_VALUES = 0xff00000c // Specialization Constants values }; // E_SH_FLAG - List of section header flags. enum E_SH_FLAG { SH_FLAG_WRITE = 0x1, SH_FLAG_ALLOC = 0x2, SH_FLAG_EXEC_INSTR = 0x4, SH_FLAG_MERGE = 0x8, SH_FLAG_STRINGS = 0x10, SH_FLAG_INFO_LINK = 0x20, SH_FLAG_LINK_ORDER = 0x40, SH_FLAG_OS_NONCONFORM = 0x100, SH_FLAG_GROUP = 0x200, SH_FLAG_TLS = 0x400, SH_FLAG_MASK_OS = 0x0ff00000, SH_FLAG_MASK_PROC = 0xf0000000, }; /******************************************************************************\ ELF-64 Data Types \******************************************************************************/ #if defined(_MSC_VER) // && (_MSC_VER < 1700) typedef unsigned __int64 Elf64_Addr; typedef unsigned __int64 Elf64_Off; typedef unsigned __int16 Elf64_Short; // Renaming Elf64_Half to Elf64_Short to avoid a conflict with Android typedef unsigned __int32 Elf64_Word; typedef __int32 Elf64_Sword; typedef unsigned __int64 Elf64_Xword; #else #if !defined(_UAPI_LINUX_ELF_H) typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Off; typedef uint32_t Elf64_Word; typedef int32_t Elf64_Sword; typedef uint64_t Elf64_Xword; #endif typedef uint16_t Elf64_Short; // Renaming Elf64_Half to Elf64_Short to avoid a conflict with Android #endif /******************************************************************************\ ELF Constants \******************************************************************************/ static const unsigned char ELF_MAG0 = 0x7f; // ELFHeader.Identity[ELF_ID_MAGIC0] static const unsigned char ELF_MAG1 = 'E'; // ELFHeader.Identity[ELF_ID_MAGIC1] static const unsigned char ELF_MAG2 = 'L'; // ELFHeader.Identity[ELF_ID_MAGIC2] static const unsigned char ELF_MAG3 = 'F'; // ELFHeader.Identity[ELF_ID_MAGIC3] static const unsigned int ELF_ALIGN_BYTES = 16; // Alignment set to 16-bytes /******************************************************************************\ ELF-64 Header \******************************************************************************/ struct SElf64Header { unsigned char Identity[ID_IDX_NUM_BYTES]; Elf64_Short Type; Elf64_Short Machine; Elf64_Word Version; Elf64_Addr EntryAddress; Elf64_Off ProgramHeadersOffset; Elf64_Off SectionHeadersOffset; Elf64_Word Flags; Elf64_Short ElfHeaderSize; Elf64_Short ProgramHeaderEntrySize; Elf64_Short NumProgramHeaderEntries; Elf64_Short SectionHeaderEntrySize; Elf64_Short NumSectionHeaderEntries; Elf64_Short SectionNameTableIndex; }; /******************************************************************************\ ELF-64 Section Header \******************************************************************************/ struct SElf64SectionHeader { Elf64_Word Name; Elf64_Word Type; Elf64_Xword Flags; Elf64_Addr Address; Elf64_Off DataOffset; Elf64_Xword DataSize; Elf64_Word Link; Elf64_Word Info; Elf64_Xword Alignment; Elf64_Xword EntrySize; }; } // namespace ELFlib intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/CLElfLib/CMakeLists.txt000066400000000000000000000052161363533017100257070ustar00rootroot00000000000000#===================== begin_copyright_notice ================================== #Copyright (c) 2017 Intel Corporation #Permission is hereby granted, free of charge, to any person obtaining a #copy of this software and associated documentation files (the #"Software"), to deal in the Software without restriction, including #without limitation the rights to use, copy, modify, merge, publish, #distribute, sublicense, and/or sell copies of the Software, and to #permit persons to whom the Software is furnished to do so, subject to #the following conditions: #The above copyright notice and this permission notice shall be included #in all copies or substantial portions of the Software. #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 AND NONINFRINGEMENT. #IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY #CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, #TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE #SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #======================= end_copyright_notice ================================== # We require cmake 3.2.0 or later cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR) # We want to organize our IDE targets into folders set_property(GLOBAL PROPERTY USE_FOLDERS ON) # This is the main CLElfLib project's cmakelists.txt file project(CLElfLib) # Set up a comprehensive source list set(CLELFLIB_READER_SRCS ${CLELFLIB_READER_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/ElfReader.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ElfReader.h" ) set(CLELFLIB_WRITER_SRCS ${CLELFLIB_WRITER_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/ElfWriter.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ElfWriter.h" ) set(CLELFLIB_SRCS ${CLELFLIB_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/CLElfTypes.h" ${CLELFLIB_READER_SRCS} ${CLELFLIB_WRITER_SRCS} ) # We want to create a lib so that everything in it can be tested add_library(CLElfLib STATIC ${CLELFLIB_SRCS}) set_target_properties(CLElfLib PROPERTIES POSITION_INDEPENDENT_CODE ON) # The following filters are added to the VS IDE representation source_group("source files" FILES "${CMAKE_CURRENT_SOURCE_DIR}/CLElfTypes.h") source_group("source files\\Reader" FILES ${CLELFLIB_READER_SRCS}) source_group("source files\\Writer" FILES ${CLELFLIB_WRITER_SRCS}) # group the igdrcl specific projects set_target_properties(CLElfLib PROPERTIES FOLDER "elf utilities") target_link_libraries(CLElfLib ${ASAN_LIB} ${TSAN_LIB}) set_property(TARGET CLElfLib APPEND_STRING PROPERTY COMPILE_FLAGS ${ASAN_FLAGS} ${TSAN_FLAGS}) intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/CLElfLib/ElfReader.cpp000066400000000000000000000234031363533017100255020ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "ElfReader.h" #include namespace CLElfLib { /******************************************************************************\ Constructor: RAIIElf::RAIIElf \******************************************************************************/ RAIIElf::RAIIElf(CElfReader *pElf) : p(pElf) {} /******************************************************************************\ Destructor: RAIIElf::RAIIElf \******************************************************************************/ RAIIElf::~RAIIElf() { if ( p != NULL ) { CElfReader::Delete(p); } } /******************************************************************************\ Constructor: CElfReader::CElfReader \******************************************************************************/ CElfReader::CElfReader( const char* pElfBinary, const size_t elfBinarySize ) { m_pNameTable = NULL; m_nameTableSize = 0; m_pElfHeader = (SElf64Header*)pElfBinary; m_pBinary = pElfBinary; // get a pointer to the string table if( m_pElfHeader ) { GetSectionData( m_pElfHeader->SectionNameTableIndex, m_pNameTable, m_nameTableSize ); } } /******************************************************************************\ Destructor: CElfReader::~CElfReader \******************************************************************************/ CElfReader::~CElfReader() { } /******************************************************************************\ Member Function: CElfReader::Create \******************************************************************************/ CElfReader* CElfReader::Create( const char* pElfBinary, const size_t elfBinarySize ) { CElfReader* pNewReader = NULL; if( IsValidElf64( pElfBinary, elfBinarySize ) ) { pNewReader = new CElfReader( pElfBinary, elfBinarySize ); } return pNewReader; } /******************************************************************************\ Member Function: CElfReader::Delete \******************************************************************************/ void CElfReader::Delete( CElfReader* &pElfReader ) { if( pElfReader ) { delete pElfReader; pElfReader = NULL; } } /******************************************************************************\ Member Function: IsValidElf64 Description: Determines if a binary is in the ELF64 format checks for invalid offsets. \******************************************************************************/ bool CElfReader::IsValidElf64( const void* pBinary, const size_t binarySize ) { bool retVal = false; SElf64Header* pElf64Header = NULL; SElf64SectionHeader* pSectionHeader = NULL; char* pNameTable = NULL; char* pEnd = NULL; size_t ourSize = 0; size_t entrySize = 0; size_t indexedSectionHeaderOffset = 0; // validate header if( pBinary && ( binarySize >= sizeof( SElf64Header ) ) ) { // calculate a pointer to the end pEnd = (char*)pBinary + binarySize; pElf64Header = (SElf64Header*)pBinary; if( ( pElf64Header->Identity[ID_IDX_MAGIC0] == ELF_MAG0 ) && ( pElf64Header->Identity[ID_IDX_MAGIC1] == ELF_MAG1 ) && ( pElf64Header->Identity[ID_IDX_MAGIC2] == ELF_MAG2 ) && ( pElf64Header->Identity[ID_IDX_MAGIC3] == ELF_MAG3 ) && ( pElf64Header->Identity[ID_IDX_CLASS] == EH_CLASS_64 ) ) { ourSize += pElf64Header->ElfHeaderSize; retVal = true; } } // validate sections if( retVal == true ) { // get the section entry size entrySize = pElf64Header->SectionHeaderEntrySize; // get an offset to the name table if( pElf64Header->SectionNameTableIndex < pElf64Header->NumSectionHeaderEntries ) { indexedSectionHeaderOffset = (size_t)pElf64Header->SectionHeadersOffset + ( pElf64Header->SectionNameTableIndex * entrySize ); if( ( (char*)pBinary + indexedSectionHeaderOffset ) <= pEnd ) { pNameTable = (char*)pBinary + indexedSectionHeaderOffset; } } for( unsigned int i = 0; i < pElf64Header->NumSectionHeaderEntries; i++ ) { indexedSectionHeaderOffset = (size_t)pElf64Header->SectionHeadersOffset + ( i * entrySize ); // check section header offset if( ( (char*)pBinary + indexedSectionHeaderOffset ) > pEnd ) { retVal = false; break; } pSectionHeader = (SElf64SectionHeader*)( (char*)pBinary + indexedSectionHeaderOffset ); // check section data if( ( (char*)pBinary + pSectionHeader->DataOffset + pSectionHeader->DataSize ) > pEnd ) { retVal = false; break; } // check section name index if( ( pNameTable + pSectionHeader->Name ) > pEnd ) { retVal = false; break; } // tally up the sizes ourSize += (size_t)pSectionHeader->DataSize; ourSize += (size_t)entrySize; } if( ourSize != binarySize ) { retVal = false; } } return retVal; } /******************************************************************************\ Member Function: GetElfHeader Description: Returns a pointer to the requested section header \******************************************************************************/ const SElf64Header* CElfReader::GetElfHeader() { return m_pElfHeader; } /******************************************************************************\ Member Function: GetSectionHeader Description: Returns a pointer to the requested section header \******************************************************************************/ const SElf64SectionHeader* CElfReader::GetSectionHeader( unsigned int sectionIndex ) { SElf64SectionHeader* pSectionHeader = NULL; size_t indexedSectionHeaderOffset = 0; size_t entrySize = m_pElfHeader->SectionHeaderEntrySize; if( sectionIndex < m_pElfHeader->NumSectionHeaderEntries ) { indexedSectionHeaderOffset = (size_t)m_pElfHeader->SectionHeadersOffset + ( sectionIndex * entrySize ); pSectionHeader = (SElf64SectionHeader*)( (char*)m_pElfHeader + indexedSectionHeaderOffset ); } return pSectionHeader; } /******************************************************************************\ Member Function: GetSectionData Description: Returns a pointer to and size of the requested section's data \******************************************************************************/ E_RETVAL CElfReader::GetSectionData( const unsigned int sectionIndex, char* &pData, size_t &dataSize ) { E_RETVAL retVal = FAILURE; const SElf64SectionHeader* pSectionHeader = GetSectionHeader( sectionIndex ); if( pSectionHeader ) { pData = (char*)m_pBinary + pSectionHeader->DataOffset; dataSize = ( size_t )pSectionHeader->DataSize; retVal = SUCCESS; } return retVal; } /******************************************************************************\ Member Function: GetSectionData Description: Returns a pointer to and size of the requested section's data \******************************************************************************/ E_RETVAL CElfReader::GetSectionData( const char* pName, char* &pData, size_t &dataSize ) { E_RETVAL retVal = FAILURE; const char* pSectionName = NULL; for( unsigned int i = 1; i < m_pElfHeader->NumSectionHeaderEntries; i++ ) { pSectionName = GetSectionName( i ); if( pSectionName && ( strcmp( pName, pSectionName ) == 0 ) ) { GetSectionData( i, pData, dataSize ); retVal = SUCCESS; break; } } return retVal; } /******************************************************************************\ Member Function: GetSectionName Description: Returns a pointer to a NULL terminated string \******************************************************************************/ const char* CElfReader::GetSectionName( unsigned int sectionIndex ) { char* pName = NULL; const SElf64SectionHeader* pSectionHeader = GetSectionHeader( sectionIndex ); if( pSectionHeader ) { pName = m_pNameTable + pSectionHeader->Name; } return pName; } } // namespace OclElfLib intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/CLElfLib/ElfReader.h000066400000000000000000000074311363533017100251520ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "CLElfTypes.h" #if defined(_WIN32) && (__KLOCWORK__ == 0) #define ELF_CALL __stdcall #else #define ELF_CALL #endif namespace CLElfLib { /******************************************************************************\ Class: CElfReader Description: Class to provide simpler interaction with the ELF standard binary object. SElf64Header defines the ELF header type and SElf64SectionHeader defines the section header type. \******************************************************************************/ class CElfReader { public: static CElfReader* ELF_CALL Create( const char* pElfBinary, const size_t elfBinarySize ); static void ELF_CALL Delete( CElfReader* &pElfObject ); static bool ELF_CALL IsValidElf64( const void* pBinary, const size_t binarySize ); const SElf64Header* ELF_CALL GetElfHeader(); const SElf64SectionHeader* ELF_CALL GetSectionHeader( unsigned int sectionIndex ); const char* ELF_CALL GetSectionName( unsigned int sectionIndex ); E_RETVAL ELF_CALL GetSectionData( const unsigned int sectionIndex, char* &pData, size_t &dataSize ); E_RETVAL ELF_CALL GetSectionData( const char* sectionName, char* &pData, size_t &dataSize ); protected: ELF_CALL CElfReader( const char* pElfBinary, const size_t elfBinarySize ); ELF_CALL ~CElfReader(); SElf64Header* m_pElfHeader; // pointer to the ELF header const char* m_pBinary; // portable ELF binary char* m_pNameTable; // pointer to the string table size_t m_nameTableSize; // size of string table in bytes }; /******************************************************************************\ Class: CElfReaderDeleter Description: Dummy class to be used with unique_ptr to call Delete on CElfReader when going out of scope. \******************************************************************************/ class CElfReaderDeleter { public: void operator()(CElfReader* ptr) const { CElfReader::Delete(ptr); } }; /******************************************************************************\ Class: RAIIElf Description: Dummy class to call the Cleanup() method on CElfReader when going out of scope. \******************************************************************************/ class RAIIElf { public: explicit RAIIElf(CElfReader *pElf); ~RAIIElf(); private: CElfReader *p; }; } // namespace CLElfLib intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/CLElfLib/ElfWriter.cpp000066400000000000000000000252661363533017100255650ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "ElfWriter.h" #include "secure_mem.h" // needed for memcpy_s on linux/android #include namespace CLElfLib { /******************************************************************************\ Constructor: CElfWriter::CElfWriter \******************************************************************************/ CElfWriter::CElfWriter( E_EH_TYPE type, E_EH_MACHINE machine, Elf64_Xword flags ) { m_type = type; m_machine = machine; m_flags = flags; m_dataSize = 0; m_numSections = 0; m_stringTableSize = 0; } /******************************************************************************\ Destructor: CElfWriter::~CElfWriter \******************************************************************************/ CElfWriter::~CElfWriter() { SSectionNode* pNode = NULL; // Walk through the section nodes while( m_nodeQueue.empty() == false ) { pNode = m_nodeQueue.front(); m_nodeQueue.pop(); // delete the node and it's data if( pNode ) { if( pNode->pData ) { delete[] pNode->pData; pNode->pData = NULL; } delete pNode; } } } /******************************************************************************\ Member Function: CElfWriter::Create \******************************************************************************/ CElfWriter* CElfWriter::Create( E_EH_TYPE type, E_EH_MACHINE machine, Elf64_Xword flags ) { CElfWriter* pWriter = new CElfWriter( type, machine, flags ); if( ( pWriter ) && ( pWriter->Initialize() != SUCCESS ) ) { Delete( pWriter ); } return pWriter; } /******************************************************************************\ Member Function: CElfWriter::Delete \******************************************************************************/ void CElfWriter::Delete( CElfWriter* &pWriter ) { if( pWriter ) { delete pWriter; pWriter = NULL; } } /******************************************************************************\ Member Function: CElfWriter::AddSection \******************************************************************************/ E_RETVAL CElfWriter::AddSection( SSectionNode* pSectionNode ) { E_RETVAL retVal = SUCCESS; SSectionNode* pNode = NULL; size_t nameSize = 0; unsigned int dataSize = 0; // The section header must be non-NULL if( pSectionNode ) { pNode = new SSectionNode(); if( !pNode ) { retVal = OUT_OF_MEMORY; } } else { retVal = FAILURE; } if( retVal == SUCCESS ) { pNode->Flags = pSectionNode->Flags; pNode->Type = pSectionNode->Type; nameSize = pSectionNode->Name.size() + 1; dataSize = pSectionNode->DataSize; pNode->Name = pSectionNode->Name; // ok to have NULL data if( dataSize > 0 ) { pNode->pData = new char[dataSize]; if( pNode->pData ) { memcpy_s( pNode->pData, dataSize, pSectionNode->pData, dataSize ); pNode->DataSize = dataSize; } else { retVal = OUT_OF_MEMORY; } } if( retVal == SUCCESS ) { // push the node onto the queue m_nodeQueue.push( pNode ); // increment the sizes for each section m_dataSize += dataSize; m_stringTableSize += nameSize; m_numSections++; } else { // cleanup allocations if( pNode ) { if( pNode->pData ) { delete[] pNode->pData; pNode->pData = NULL; } delete pNode; } } } return retVal; } /******************************************************************************\ Member Function: CElfWriter::ResolveBinary \******************************************************************************/ E_RETVAL CElfWriter::ResolveBinary( char* const pBinary, size_t& binarySize ) { E_RETVAL retVal = SUCCESS; SSectionNode* pNode = NULL; SElf64SectionHeader* pCurSectionHeader = NULL; char* pData = NULL; char* pStringTable = NULL; char* pCurString = NULL; m_totalBinarySize = sizeof( SElf64Header ) + ( ( m_numSections + 1 ) * sizeof( SElf64SectionHeader ) ) + // +1 to account for string table entry m_dataSize + m_stringTableSize; if( pBinary ) { // get a pointer to the first section header pCurSectionHeader = (SElf64SectionHeader*)( pBinary + sizeof( SElf64Header ) ); // get a pointer to the data pData = pBinary + sizeof( SElf64Header ) + ( ( m_numSections + 1 ) * sizeof( SElf64SectionHeader ) ); // +1 to account for string table entry // get a pointer to the string table pStringTable = pBinary + sizeof( SElf64Header ) + ( ( m_numSections + 1 ) * sizeof( SElf64SectionHeader ) ) + // +1 to account for string table entry m_dataSize ; pCurString = pStringTable; // Walk through the section nodes while( m_nodeQueue.empty() == false ) { pNode = m_nodeQueue.front(); if( pNode ) { m_nodeQueue.pop(); // Copy data into the section header memset( pCurSectionHeader, 0, sizeof( SElf64SectionHeader ) ); pCurSectionHeader->Type = pNode->Type; pCurSectionHeader->Flags = pNode->Flags; pCurSectionHeader->DataSize = pNode->DataSize; pCurSectionHeader->DataOffset = pData - pBinary; pCurSectionHeader->Name = (Elf64_Word)( pCurString - pStringTable ); pCurSectionHeader = (SElf64SectionHeader*)( (unsigned char*)pCurSectionHeader + sizeof( SElf64SectionHeader ) ); // copy the data, move the data pointer memcpy_s( pData, pNode->DataSize, pNode->pData, pNode->DataSize ); pData += pNode->DataSize; // copy the name into the string table, move the string pointer if ( pNode->Name.size() > 0 ) { memcpy_s( pCurString, pNode->Name.size(), pNode->Name.c_str(), pNode->Name.size() ); pCurString += pNode->Name.size(); } *(pCurString++) = '\0'; // delete the node and it's data if( pNode ) { if( pNode->pData ) { delete[] pNode->pData; pNode->pData = NULL; } delete pNode; } } } // add the string table section header SElf64SectionHeader stringSectionHeader = { 0 }; stringSectionHeader.Type = SH_TYPE_STR_TBL; stringSectionHeader.Flags = 0; stringSectionHeader.DataOffset = pStringTable - pBinary; stringSectionHeader.DataSize = m_stringTableSize; stringSectionHeader.Name = 0; // Copy into the last section header memcpy_s( pCurSectionHeader, sizeof( SElf64SectionHeader ), &stringSectionHeader, sizeof( SElf64SectionHeader ) ); // Add to our section number m_numSections++; // patch up the ELF header retVal = PatchElfHeader( pBinary ); } if( retVal == SUCCESS ) { binarySize = m_totalBinarySize; } return retVal; } /******************************************************************************\ Member Function: CElfWriter::Initialize \******************************************************************************/ E_RETVAL CElfWriter::Initialize() { E_RETVAL retVal = SUCCESS; SSectionNode emptySection; // Add an empty section 0 (points to "no-bits") AddSection( &emptySection ); return retVal; } /******************************************************************************\ Member Function: CElfWriter::PatchElfHeader \******************************************************************************/ E_RETVAL CElfWriter::PatchElfHeader( char* const pBinary ) { E_RETVAL retVal = SUCCESS; SElf64Header* pElfHeader = (SElf64Header*)pBinary; if( pElfHeader ) { // Setup the identity memset( pElfHeader, 0x00, sizeof( SElf64Header ) ); pElfHeader->Identity[ID_IDX_MAGIC0] = ELF_MAG0; pElfHeader->Identity[ID_IDX_MAGIC1] = ELF_MAG1; pElfHeader->Identity[ID_IDX_MAGIC2] = ELF_MAG2; pElfHeader->Identity[ID_IDX_MAGIC3] = ELF_MAG3; pElfHeader->Identity[ID_IDX_CLASS] = EH_CLASS_64; pElfHeader->Identity[ID_IDX_VERSION] = EH_VERSION_CURRENT; // Add other non-zero info pElfHeader->Type = m_type; pElfHeader->Machine = m_machine; pElfHeader->Flags = (unsigned int)m_flags; pElfHeader->ElfHeaderSize = sizeof( SElf64Header ); pElfHeader->SectionHeaderEntrySize = sizeof( SElf64SectionHeader ); pElfHeader->NumSectionHeaderEntries = (Elf64_Short)m_numSections; pElfHeader->SectionHeadersOffset = (unsigned int)( sizeof( SElf64Header ) ); pElfHeader->SectionNameTableIndex = m_numSections-1; // last index } return retVal; } } // namespace OclElfLib intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/CLElfLib/ElfWriter.h000066400000000000000000000072531363533017100252260ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "CLElfTypes.h" #include #include #if defined(_WIN32) && (__KLOCWORK__ == 0) #define ELF_CALL __stdcall #else #define ELF_CALL #endif using namespace std; namespace CLElfLib { static const unsigned int g_scElfHeaderAlignment = 16; // allocation alignment restriction static const unsigned int g_scInitialElfSize = 2048; // initial elf size (in bytes) static const unsigned int g_scInitNumSectionHeaders = 8; struct SSectionNode { E_SH_TYPE Type; unsigned int Flags; string Name; char* pData; unsigned int DataSize; SSectionNode() { Type = SH_TYPE_NULL; Flags = 0; pData = NULL; DataSize = 0; } ~SSectionNode() { } }; /******************************************************************************\ Class: CElfWriter Description: Class to provide simpler interaction with the ELF standard binary object. SElf64Header defines the ELF header type and SElf64SectionHeader defines the section header type. \******************************************************************************/ class CElfWriter { public: static CElfWriter* ELF_CALL Create( E_EH_TYPE type, E_EH_MACHINE machine, Elf64_Xword flags ); static void ELF_CALL Delete( CElfWriter* &pElfWriter ); E_RETVAL ELF_CALL AddSection( SSectionNode* pSectionNode ); E_RETVAL ELF_CALL ResolveBinary( char* const pBinary, size_t& dataSize ); E_RETVAL ELF_CALL Initialize(); E_RETVAL ELF_CALL PatchElfHeader( char* const pBinary ); protected: ELF_CALL CElfWriter( E_EH_TYPE type, E_EH_MACHINE machine, Elf64_Xword flags ); ELF_CALL ~CElfWriter(); E_EH_TYPE m_type; E_EH_MACHINE m_machine; Elf64_Xword m_flags; std::queue m_nodeQueue; unsigned int m_dataSize; unsigned int m_numSections; size_t m_stringTableSize; size_t m_totalBinarySize; }; /******************************************************************************\ Class: CElfWriterDeleter Description: Dummy class to be used with unique_ptr to call Delete on CElfReader when going out of scope. \******************************************************************************/ class CElfWriterDeleter { public: void operator()(CElfWriter* ptr) const { CElfWriter::Delete(ptr); } }; } // namespace ELFLib intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/CMakeLists.txt000066400000000000000000000146641363533017100243420ustar00rootroot00000000000000 set(IGC_BUILD__PROJ__AdaptorOCL "${IGC_BUILD__PROJ_NAME_PREFIX}AdaptorOCL") set(IGC_BUILD__PROJ__AdaptorOCL "${IGC_BUILD__PROJ__AdaptorOCL}" PARENT_SCOPE) # set directly set(IGC_BUILD__PROJ_LABEL__AdaptorOCL "AdaptorOCL") include_directories("${CMAKE_CURRENT_SOURCE_DIR}") #include_directories("${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_shared/executable_format") set(IGC_BUILD__SRC__AdaptorOCL "${CMAKE_CURRENT_SOURCE_DIR}/Upgrader/llvm${LLVM_VERSION_MAJOR}/Upgrader.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Upgrader/llvm${LLVM_VERSION_MAJOR}/BitcodeReader.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/UnifyIROCL.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MoveStaticAllocas.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/cmc.cpp" ) if(IGC_BUILD__SPIRV_ENABLED) list(APPEND IGC_BUILD__SRC__AdaptorOCL SPIRV/libSPIRV/OpenCL.std.h SPIRV/libSPIRV/OpenCL.stdfuncs.h SPIRV/libSPIRV/SPIRVBasicBlock.h SPIRV/libSPIRV/SPIRVDebug.h SPIRV/libSPIRV/SPIRVDecorate.h SPIRV/libSPIRV/SPIRVEntry.h SPIRV/libSPIRV/SPIRVEnum.h SPIRV/libSPIRV/SPIRVError.h SPIRV/libSPIRV/SPIRVErrorEnum.h SPIRV/libSPIRV/SPIRVExtInst.h SPIRV/libSPIRV/SPIRVFunction.h SPIRV/libSPIRV/SPIRVInstruction.h SPIRV/libSPIRV/SPIRVModule.h SPIRV/libSPIRV/SPIRVOpCode.h SPIRV/libSPIRV/SPIRVOpCodeEnum.h SPIRV/libSPIRV/SPIRVBuiltinEnum.h SPIRV/libSPIRV/SPIRVStream.h SPIRV/libSPIRV/SPIRVType.h SPIRV/libSPIRV/SPIRVUtil.h SPIRV/libSPIRV/SPIRVValue.h SPIRV/libSPIRV/spirv.hpp SPIRV/SPIRVconsum.h SPIRV/SPIRVInternal.h SPIRV/libSPIRV/SPIRVBasicBlock.cpp SPIRV/libSPIRV/SPIRVDebug.cpp SPIRV/libSPIRV/SPIRVDecorate.cpp SPIRV/libSPIRV/SPIRVEntry.cpp SPIRV/libSPIRV/SPIRVFunction.cpp SPIRV/libSPIRV/SPIRVInstruction.cpp SPIRV/libSPIRV/SPIRVModule.cpp SPIRV/libSPIRV/SPIRVStream.cpp SPIRV/libSPIRV/SPIRVType.cpp SPIRV/libSPIRV/SPIRVValue.cpp SPIRV/SPIRVReader.cpp SPIRV/SPIRVUtil.cpp SPIRV/libSPIRV/SPIRV.DebugInfo.h SPIRV/libSPIRV/SPIRV.DebugInfofuncs.h SPIRV/libSPIRV/SPIRVDebugInfoExt.h ) endif(IGC_BUILD__SPIRV_ENABLED) # NOTE: Exported functions must be added to final libraries/executables directly. set(IGC_BUILD__SRC__IGC_AdaptorOCL "${CMAKE_CURRENT_SOURCE_DIR}/dllInterfaceCompute.cpp" ) set(IGC_BUILD__HDR__IGC_AdaptorOCL "") list(APPEND IGC_BUILD__SRC__IGC_AdaptorOCL "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/igc_features_and_workarounds_impl.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/igc_ocl_device_ctx_impl.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/igc_ocl_translation_ctx_impl.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/ocl_gen_binary_impl.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/ocl_translation_output_impl.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/gt_system_info_impl.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/platform_impl.cpp" ${CIF_SOURCES_EXPORT_ABSOLUTE_PATH}) list(APPEND IGC_BUILD__HDR__IGC_AdaptorOCL "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/igc_features_and_workarounds_impl.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/igc_ocl_device_ctx_impl.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/igc_ocl_translation_ctx_impl.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/ocl_gen_binary_impl.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/ocl_translation_output_impl.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/gt_system_info_impl.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/impl/platform_impl.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/igc_features_and_workarounds.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/igc_ocl_device_ctx.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/igc_ocl_translation_ctx.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/ocl_gen_binary.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/ocl_translation_output.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/gt_system_info.h" "${CMAKE_CURRENT_SOURCE_DIR}/ocl_igc_interface/platform.h" ${CIF_HEADERS_ABSOLUTE_PATH}) set(IGC_BUILD__SRC__IGC_AdaptorOCL ${IGC_BUILD__SRC__IGC_AdaptorOCL} PARENT_SCOPE) # set directly set(IGC_BUILD__HDR__IGC_AdaptorOCL ${IGC_BUILD__HDR__IGC_AdaptorOCL} PARENT_SCOPE) # Will be set in IGC's level cmake set(IGC_BUILD__HDR__AdaptorOCL "${CMAKE_CURRENT_SOURCE_DIR}/../AdaptorCommon/customApi.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/../AdaptorCommon/ProcessFuncAttributes.h" "${CMAKE_CURRENT_SOURCE_DIR}/OCL/KernelAnnotations.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/OCL/CommandStream/SamplerTypes.h" "${CMAKE_CURRENT_SOURCE_DIR}/OCL/CommandStream/SurfaceTypes.h" "${CMAKE_CURRENT_SOURCE_DIR}/DriverInfoOCL.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/igcmc.h" "${CMAKE_CURRENT_SOURCE_DIR}/cmc.h" "${CMAKE_CURRENT_SOURCE_DIR}/UnifyIROCL.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/MoveStaticAllocas.h" #"${IGC_BUILD__COMMON_COMPILER_DIR}/adapters/d3d10/API/USC_d3d10.h" #"${IGC_BUILD__COMMON_COMPILER_DIR}/adapters/d3d10/usc_d3d10_umd.h" #"${IGC_BUILD__COMMON_COMPILER_DIR}/adapters/d3d9/api/usc_d3d9.h" "${IGC_BUILD__COMMON_COMPILER_DIR}/API/ErrorCode.h" "${IGC_BUILD__COMMON_COMPILER_DIR}/API/SurfaceFormats.h" "${IGC_BUILD__COMMON_COMPILER_DIR}/API/usc.h" "${IGC_BUILD__COMMON_COMPILER_DIR}/API/usc_config.h" "${IGC_BUILD__COMMON_COMPILER_DIR}/API/usc_debugControl.h" "${IGC_BUILD__COMMON_COMPILER_DIR}/API/usc_gen7.h" "${IGC_BUILD__COMMON_COMPILER_DIR}/API/usc_gen8.h" "${IGC_BUILD__COMMON_COMPILER_DIR}/API/usc_gen9.h" ) if(IGC_BUILD__SPIRV/ENABLED) list(APPEND IGC_BUILD__HDR__AdaptorOCL "SPIRV/SPIRVconsum.h" ) endif() igc_regex_escape(_reSrcDir "${CMAKE_CURRENT_SOURCE_DIR}") add_library("${IGC_BUILD__PROJ__AdaptorOCL}" STATIC ${IGC_BUILD__SRC__AdaptorOCL} ${IGC_BUILD__HDR__AdaptorOCL} ) add_dependencies("${IGC_BUILD__PROJ__AdaptorOCL}" "${IGC_BUILD__PROJ__GenISAIntrinsics}") set_property(TARGET "${IGC_BUILD__PROJ__AdaptorOCL}" PROPERTY PROJECT_LABEL "${IGC_BUILD__PROJ_LABEL__AdaptorOCL}") igc_sg_register( IGC__AdaptorOCL "DriverInterface\\OCL" FILES ${IGC_BUILD__SRC__IGC_AdaptorOCL} ${IGC_BUILD__HDR__IGC_AdaptorOCL} ) intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/DriverInfoOCL.hpp000066400000000000000000000072401363533017100247100ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Compiler/CISACodeGen/DriverInfo.hpp" namespace TC { /// caps common to all OCL runtimes class CDriverInfoOCLCommon : public IGC::CDriverInfo { public: bool AllowUnsafeHalf() const override { return false; } bool AllowSendFusion() const override { return false; } bool SupportsIEEEMinMax() const override { return true; } bool SupportsPreciseMath() const override { return true; } bool NeedCheckContractionAllowed() const override { return true; } bool NeedI64BitDivRem() const override { return true; } bool HasMemoryIntrinsics() const override { return true; } bool HasNonNativeLoadStore() const override { return true; } bool NeedLoweringInlinedConstants() const override { return true; } bool benefitFromTypeDemotion() const override { return true; } bool benefitFromPreRARematFlag() const override { return true; } bool NeedExtraPassesAfterAlwaysInlinerPass() const override { return true; } bool enableVISAPreRAScheduler() const override { return true; } bool NeedWAToTransformA32MessagesToA64() const override{ return true; } bool WALoadStorePatternMatch() const override { return true; } bool WADisableCustomPass() const override { return true; } bool WAEnableMemOpt2ForOCL() const override { return true; } unsigned int GetLoopUnrollThreshold() const override { return 1280; } bool Enable64BitEmu() const override { return true; } bool NeedIEEESPDiv() const override { return true; } // Not needed as OCL doesn't go through emitStore3DInner bool splitUnalignedVectors() const override { return false; } bool supportsStatelessSpacePrivateMemory() const override { return true; } bool NeedFP64(PRODUCT_FAMILY productFamily) const override { #if defined(__linux__) if (IGC_IS_FLAG_ENABLED(EnableDPEmulation)) { return true; } #endif return false; } }; // In case some cpas are specific to NEO class CDriverInfoOCLNEO : public CDriverInfoOCLCommon { public: bool SupportsStatelessToStatefullBufferTransformation() const override { return true; } unsigned getVISAPreRASchedulerCtrl() const override { return 6; } bool SupportStatefulToken() const override { return true; } bool SupportInlineAssembly() const override { return true; } }; }//namespace TC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/GlobalData.h000066400000000000000000000035621363533017100237400ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "sku_wa.h" #include "igfxfmid.h" #include "gtsysinfo.h" /*****************************************************************************\ Global Data: Platform, Sku Features, and Workaround Table \*****************************************************************************/ typedef struct _SGlobalData { const PLATFORM* pPlatform; // Target platform const SKU_FEATURE_TABLE* pSkuTable; // SKU table const WA_TABLE* pWaTable; // WA table const GT_SYSTEM_INFO* pSysInfo; // GtType // Profiling timer resolution depending on platform float ProfilingTimerResolution; } SGlobalData; intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/MoveStaticAllocas.cpp000066400000000000000000000056741363533017100256640ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "MoveStaticAllocas.h" #include "common/LLVMWarningsPush.hpp" #include #include #include #include #include "common/LLVMWarningsPop.hpp" using namespace llvm; using namespace IGC; // Register pass to igc-opt #define PASS_FLAG "igc-move-static-allocas" #define PASS_DESCRIPTION "Move static allocas to entry basic block of the function" #define PASS_CFG_ONLY false #define PASS_ANALYSIS false IGC_INITIALIZE_PASS_BEGIN(MoveStaticAllocas, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS) IGC_INITIALIZE_PASS_END(MoveStaticAllocas, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS) char MoveStaticAllocas::ID = 0; // This function is copied from LLVM's InlineFunction. static bool allocaWouldBeStaticInEntry(const AllocaInst *AI) { return isa(AI->getArraySize()) && !AI->isUsedWithInAlloca(); } MoveStaticAllocas::MoveStaticAllocas() : FunctionPass(ID) { initializeMoveStaticAllocasPass(*PassRegistry::getPassRegistry()); } bool MoveStaticAllocas::runOnFunction(llvm::Function &F) { std::vector staticAllocas; // Note: we are also moving static allocas that are already in the entry BB. for (auto inst = inst_begin(F), endInst = inst_end(F); inst != endInst; ++inst) { if (AllocaInst* allocaInst = dyn_cast(&*inst)) { if (allocaInst->isStaticAlloca() || allocaWouldBeStaticInEntry(allocaInst)) { staticAllocas.push_back(allocaInst); } } } for (auto I = staticAllocas.rbegin(), E = staticAllocas.rend(); I != E; ++I) { (*I)->moveBefore(&*F.getEntryBlock().getFirstInsertionPt()); } return staticAllocas.size() > 0; } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/MoveStaticAllocas.h000066400000000000000000000042711363533017100253210ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Compiler/CISACodeGen/helper.h" #include "Compiler/CISACodeGen/ShaderCodeGen.hpp" #include "Compiler/MetaDataUtilsWrapper.h" #include "Compiler/MetaDataApi/MetaDataApi.h" #include "common/LLVMWarningsPush.hpp" #include #include #include #include "common/LLVMWarningsPop.hpp" namespace IGC { /* This pass searches for "static" alloca instructions in function that are not in the entry block and moves them. This prevents llvm from inserting @llvm.stacksave and @llvm.stackrestore that are not handled by IGC. */ class MoveStaticAllocas : public llvm::FunctionPass { public: static char ID; MoveStaticAllocas(); ~MoveStaticAllocas() {} virtual llvm::StringRef getPassName() const override { return "MoveStaticAllocasPass"; } virtual bool runOnFunction(llvm::Function &F) override; }; } // namespace IGCintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/000077500000000000000000000000001363533017100222045ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/BuiltinResource.h000066400000000000000000000027411363533017100254770ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //{{NO_DEPENDENCIES}} // Used by BuiltinResource.rc // #define OCL_BC_START 120 #define OCL_BC_32 120 #define OCL_BC_64 121 #define OCL_BC 122 #define OCL_BC_END 125 intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/BuiltinResource.rc000066400000000000000000000031051363533017100256470ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "BuiltinResource.h" ///////////////////////////////////////////////////////////////////////////// // // BC // OCL_BC BC "OCLBiFImpl.bc" OCL_BC_32 BC "IGCsize_t_32.bc" OCL_BC_64 BC "IGCsize_t_64.bc" ///////////////////////////////////////////////////////////////////////////// intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/CommandStream/000077500000000000000000000000001363533017100247365ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/CommandStream/SamplerTypes.h000066400000000000000000000062321363533017100275420ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once namespace iOpenCL { /*****************************************************************************\ ENUM: SAMPLER_TEXTURE_ADDRESS_MODE_TYPE \*****************************************************************************/ enum SAMPLER_TEXTURE_ADDRESS_MODE { SAMPLER_TEXTURE_ADDRESS_MODE_WRAP = 0, SAMPLER_TEXTURE_ADDRESS_MODE_MIRROR = 1, SAMPLER_TEXTURE_ADDRESS_MODE_CLAMP = 2, SAMPLER_TEXTURE_ADDRESS_MODE_BORDER = 3, SAMPLER_TEXTURE_ADDRESS_MODE_MIRRORONCE = 4, SAMPLER_TEXTURE_ADDRESS_MODE_MIRROR101 = 5, NUM_SAMPLER_TEXTURE_ADDRESS_MODES }; /*****************************************************************************\ ENUM: SAMPLER_MAPFILTER_TYPE \*****************************************************************************/ enum SAMPLER_MAPFILTER_TYPE { SAMPLER_MAPFILTER_POINT = 0, SAMPLER_MAPFILTER_LINEAR = 1, SAMPLER_MAPFILTER_ANISOTROPIC = 2, SAMPLER_MAPFILTER_GAUSSIANQUAD = 3, SAMPLER_MAPFILTER_PYRAMIDALQUAD = 4, SAMPLER_MAPFILTER_MONO = 5, NUM_SAMPLER_MAPFILTER_TYPES }; /*****************************************************************************\ ENUM: SAMPLER_MIPFILTER_TYPE \*****************************************************************************/ enum SAMPLER_MIPFILTER_TYPE { SAMPLER_MIPFILTER_POINT, SAMPLER_MIPFILTER_LINEAR, SAMPLER_MIPFILTER_NONE, NUM_SAMPLER_MIPFILTER_TYPES }; /*****************************************************************************\ ENUM: SAMPLER_COMPARE_FUNC_TYPE \*****************************************************************************/ enum SAMPLER_COMPARE_FUNC_TYPE { SAMPLER_COMPARE_FUNC_ALWAYS, SAMPLER_COMPARE_FUNC_NEVER, SAMPLER_COMPARE_FUNC_LESS, SAMPLER_COMPARE_FUNC_EQUAL, SAMPLER_COMPARE_FUNC_LEQUAL, SAMPLER_COMPARE_FUNC_GREATER, SAMPLER_COMPARE_FUNC_NOTEQUAL, SAMPLER_COMPARE_FUNC_GEQUAL, NUM_SAMPLER_COMPARE_FUNC_TYPES }; } // namespace iCBE intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/CommandStream/SurfaceTypes.h000066400000000000000000000070411363533017100275260ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once namespace iOpenCL { /*****************************************************************************\ ENUM: RESOURCE_ALLOCATION_TYPE \*****************************************************************************/ enum RESOURCE_ALLOCATION_TYPE { RESOURCE_ALLOCATION_LINEAR, RESOURCE_ALLOCATION_TILED_X, RESOURCE_ALLOCATION_TILED_Y, NUM_RESOURCE_ALLOCATION_TYPES }; /*****************************************************************************\ ENUM: RESOURCE_MIPMAP_LAYOUT_MODE \*****************************************************************************/ enum RESOURCE_MIPMAP_LAYOUT_MODE { RESOURCE_MIPMAP_LAYOUT_BELOW, RESOURCE_MIPMAP_LAYOUT_RIGHT, NUM_RESOURCE_MIPMAP_LAYOUT_MODES }; /*****************************************************************************\ ENUM: RESOURCE_SAMPLE_PATTERN \*****************************************************************************/ enum RESOURCE_SAMPLE_PATTERN { RESOURCE_SAMPLE_PATTERN_STANDARD, RESOURCE_SAMPLE_PATTERN_CENTER, NUM_RESOURCE_SAMPLE_PATTERNS }; /*****************************************************************************\ ENUM: SURFACE_TYPE \*****************************************************************************/ enum SURFACE_TYPE { SURFACE_UNKNOWN = 0, SURFACE_NULL = 1, SURFACE_1D = 2, SURFACE_1D_ARRAY = 3, SURFACE_2D = 4, SURFACE_2D_ARRAY = 5, SURFACE_3D = 6, SURFACE_CUBE = 7, SURFACE_CUBE_ARRAY = 8, SURFACE_CONSTANT = 9, SURFACE_BUFFER = 10, SURFACE_2D_MEDIA = 11, SURFACE_2D_MEDIA_BLOCK = 12, NUM_SURFACE_TYPES }; /*****************************************************************************\ ENUM: SURFACE_CUBE_FACE_ENABLES \*****************************************************************************/ enum SURFACE_CUBE_FACE_ENABLES { SURFACE_CUBE_FACE_ENABLE_NONE = 0x00000000, SURFACE_CUBE_FACE_ENABLE_NEGATIVE_X = 0x00000001, SURFACE_CUBE_FACE_ENABLE_POSITIVE_X = 0x00000002, SURFACE_CUBE_FACE_ENABLE_NEGATIVE_Y = 0x00000004, SURFACE_CUBE_FACE_ENABLE_POSITIVE_Y = 0x00000008, SURFACE_CUBE_FACE_ENABLE_NEGATIVE_Z = 0x00000010, SURFACE_CUBE_FACE_ENABLE_POSITIVE_Z = 0x00000020, SURFACE_CUBE_FACE_ENABLE_ALL = 0x0000003F, }; } // namespace iCBEintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/KernelAnnotations.hpp000066400000000000000000000243131363533017100263560ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #ifndef _KERNEL_ANNOTATIONS_H_ #define _KERNEL_ANNOTATIONS_H_ #include #include "patch_list.h" namespace iOpenCL { enum POINTER_ADDRESS_SPACE { KERNEL_ARGUMENT_ADDRESS_SPACE_INVALID, KERNEL_ARGUMENT_ADDRESS_SPACE_GLOBAL, KERNEL_ARGUMENT_ADDRESS_SPACE_CONSTANT, KERNEL_ARGUMENT_ADDRESS_SPACE_PRIVATE, KERNEL_ARGUMENT_ADDRESS_SPACE_LOCAL, KERNEL_ARGUMENT_ADDRESS_SPACE_DEVICE_QUEUE, ADDRESS_SPACE_INTERNAL_DEFAULT_DEVICE_QUEUE, ADDRESS_SPACE_INTERNAL_EVENT_POOL, ADDRESS_SPACE_INTERNAL_PRINTF, NUM_KERNEL_ARGUMENT_ADDRESS_SPACE }; enum TYPE_FORMAT { TYPE_FORMAT_INVALID, TYPE_FORMAT_FLOAT, TYPE_FORMAT_SINT, TYPE_FORMAT_UINT, NUM_TYPE_FORMATS }; struct KernelAnnotation { DWORD AnnotationSize; }; // Generated by the frontend struct KernelArgumentAnnotation : KernelAnnotation { DWORD ArgumentNumber; }; // Generated by frontend - completed by backend struct PointerArgumentAnnotation : KernelArgumentAnnotation { POINTER_ADDRESS_SPACE AddressSpace; bool IsStateless; DWORD BindingTableIndex; DWORD PayloadPosition; DWORD PayloadSizeInBytes; DWORD LocationIndex; DWORD LocationCount; bool IsEmulationArgument; bool IsBindlessAccess; static bool compare( const PointerArgumentAnnotation* a, const PointerArgumentAnnotation* b ) { return ( a->PayloadPosition < b->PayloadPosition ); } }; // Should be used for __local address space pointer arguments, as it // contains rather different fields from PointerArgumentAnnotation struct LocalArgumentAnnotation : KernelArgumentAnnotation { DWORD Alignment; DWORD PayloadPosition; DWORD PayloadSizeInBytes; DWORD LocationIndex; DWORD LocationCount; }; // Generated by frontend - completed by backend struct PointerInputAnnotation : KernelAnnotation { POINTER_ADDRESS_SPACE AddressSpace; bool IsStateless; DWORD BindingTableIndex; DWORD PayloadPosition; DWORD PayloadSizeInBytes; DWORD ArgumentNumber; }; struct PrivateInputAnnotation : PointerInputAnnotation { DWORD PerThreadPrivateMemorySize; }; // Generated by frontend - completed by backend struct ConstantArgumentAnnotation : KernelArgumentAnnotation { DWORD TypeSize; DWORD Offset; DWORD PayloadPosition; DWORD PayloadSizeInBytes; DWORD LocationIndex; DWORD LocationCount; bool IsEmulationArgument; }; // Generated by frontend - completed by backend struct ConstantInputAnnotation : KernelAnnotation { // ConstantInputAnnotations, while not being argument annotations, // may refer to arguments. DWORD ArgumentNumber; DWORD TypeSize; DWORD ConstantType; DWORD Offset; DWORD PayloadPosition; DWORD PayloadSizeInBytes; DWORD LocationIndex; DWORD LocationCount; }; // Generated by frontend - completed by backend struct ImageArgumentAnnotation : KernelArgumentAnnotation { IMAGE_MEMORY_OBJECT_TYPE ImageType; bool Writeable; bool IsFixedBindingTableIndex; DWORD BindingTableIndex; DWORD LocationIndex; DWORD LocationCount; DWORD PayloadPosition; bool AccessedByIntCoords; bool AccessedByFloatCoords; bool IsBindlessAccess; bool IsEmulationArgument; }; struct SamplerInputAnnotation : KernelAnnotation { SAMPLER_OBJECT_TYPE SamplerType; DWORD SamplerTableIndex; bool NormalizedCoords; SAMPLER_MAPFILTER_TYPE MagFilterType; SAMPLER_MAPFILTER_TYPE MinFilterType; SAMPLER_MIPFILTER_TYPE MipFilterType; SAMPLER_TEXTURE_ADDRESS_MODE TCXAddressMode; SAMPLER_TEXTURE_ADDRESS_MODE TCYAddressMode; SAMPLER_TEXTURE_ADDRESS_MODE TCZAddressMode; SAMPLER_COMPARE_FUNC_TYPE CompareFunc; float BorderColorR; float BorderColorG; float BorderColorB; float BorderColorA; }; // Generated by frontend - completed by backend struct SamplerArgumentAnnotation : KernelArgumentAnnotation { // Generated by the front end SAMPLER_OBJECT_TYPE SamplerType; // Generated by the backend DWORD SamplerTableIndex; DWORD LocationIndex; DWORD LocationCount; DWORD PayloadPosition; bool IsBindlessAccess; bool IsEmulationArgument; }; // Annotation for format string of printf struct PrintfStringAnnotation : KernelAnnotation { DWORD Index; DWORD StringSize; char *StringData; }; // Annotation for printf output buffer. struct PrintfBufferAnnotation : KernelArgumentAnnotation { DWORD Index; DWORD DataSize; DWORD PayloadPosition; }; // Annotation for sync buffer. struct SyncBufferAnnotation : KernelArgumentAnnotation { DWORD DataSize; DWORD PayloadPosition; }; // Generated by front end struct KernelConstantRegisterAnnotation { DWORD Index; DWORD Channel; }; struct InitConstantAnnotation { std::vector InlineData; int Alignment; }; struct InitGlobalAnnotation { std::vector InlineData; int Alignment; }; struct ConstantPointerAnnotation { unsigned PointerBufferIndex; unsigned PointerOffset; unsigned PointeeAddressSpace; unsigned PointeeBufferIndex; }; struct GlobalPointerAnnotation { unsigned PointerBufferIndex; unsigned PointerOffset; unsigned PointeeAddressSpace; unsigned PointeeBufferIndex; }; struct ThreadPayload { bool HasLocalIDx = false; bool HasLocalIDy = false; bool HasLocalIDz = false; bool HasGlobalIDOffset = false; bool HasGroupID = false; bool HasLocalID = false; bool HasFlattenedLocalID = false; bool CompiledForIndirectPayloadStorage = false; bool UnusedPerThreadConstantPresent = false; bool HasStageInGridOrigin = false; bool HasStageInGridSize = false; bool PassInlineData = false; uint32_t OffsetToSkipPerThreadDataLoad = 0; uint32_t OffsetToSkipSetFFIDGP = 0; }; struct ExecutionEnivronment { DWORD CompiledSIMDSize = 0; DWORD CompiledSubGroupsNumber = 0; //legacy design:hold all ScratchSpaceUsage //new design: hold spillfill+callstack+GTPin //Todo: rename it to m_PerThreadScratchSpaceSlot0 DWORD PerThreadScratchSpace = 0; //DWORD PerThreadScratchUseGtpin = 0; //legacy design:not used //new design: hold private memory used by shader if non-ZERO DWORD PerThreadScratchSpaceSlot1 = 0; //legacy design:not used //new design: hold private memory used by shader if non-ZERO DWORD SumFixedTGSMSizes = 0; bool HasDeviceEnqueue = false; uint32_t HasBarriers = 0; bool IsSingleProgramFlow = false; //DWORD PerSIMDLanePrivateMemorySize = 0; bool HasFixedWorkGroupSize = false; bool HasReadWriteImages = false; bool DisableMidThreadPreemption = false; bool IsInitializer = false; bool IsFinalizer = false; bool SubgroupIndependentForwardProgressRequired = false; bool CompiledForGreaterThan4GBBuffers = false; DWORD FixedWorkgroupSize[3] = {}; DWORD NumGRFRequired = 0; DWORD WorkgroupWalkOrder[3] = {}; bool HasGlobalAtomics = false; }; struct KernelTypeProgramBinaryInfo { DWORD Type; std::string KernelName; }; struct KernelArgumentInfoAnnotation { std::string AddressQualifier; std::string AccessQualifier; std::string ArgumentName; std::string TypeName; std::string TypeQualifier; }; struct StartGASAnnotation { DWORD Offset; DWORD gpuPointerSizeInBytes; }; struct WindowSizeGASAnnotation { DWORD Offset; }; struct PrivateMemSizeAnnotation { DWORD Offset; }; typedef std::vector::const_iterator PointerInputIterator; typedef std::vector::const_iterator PointerArgumentIterator; typedef std::vector::const_iterator LocalArgumentIterator; typedef std::vector::const_iterator ConstantInputIterator; typedef std::vector::const_iterator ConstantArgumentIterator; typedef std::vector::const_iterator SamplerInputIterator; typedef std::vector::const_iterator SamplerArgumentIterator; typedef std::vector::const_iterator ImageArgumentIterator; typedef std::vector::const_iterator InitConstantIterator; typedef std::vector::const_iterator KernelArgumentInfoIterator; typedef std::vector::const_iterator PrintfStringIterator; } #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/LoadBuffer.cpp000066400000000000000000000114361363533017100247260ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "AdaptorOCL/OCL/LoadBuffer.h" #include "common/LLVMWarningsPush.hpp" #include #include #include "common/LLVMWarningsPop.hpp" #include using namespace llvm; #ifdef LLVM_ON_UNIX #include #include MemoryBuffer *llvm::LoadBufferFromResource(const char *pResName, const char *pResType) { // Symbol Name is _ char name[73]; // 64 + 9 for prefix char size_name[78]; // 64 + 9 for prefix + 5 for suffix void *module; void *symbol; uint32_t size; snprintf(name, sizeof(name), "_igc_bif_%s_%s", pResType, &pResName[1]); snprintf(size_name, sizeof(size_name), "_igc_bif_%s_%s_size", pResType, &pResName[1]); module = RTLD_DEFAULT; symbol = dlsym(module, size_name); if (!symbol) { return NULL; } size = *(uint32_t *)symbol; symbol = dlsym(module, name); if (!symbol) { return NULL; } // Create a copy of the buffer for the caller. This copy is managed return MemoryBuffer::getMemBufferCopy(StringRef((char *)symbol, size)).release(); } #endif #ifdef WIN32 #include // Windows.h defines MemoryFence as _mm_mfence, but this conflicts with llvm::sys::MemoryFence #undef MemoryFence HRSRC FindResourceCompat(HMODULE hMod, const char * pResName, const char * pResType) { std::wstring resNameW; std::wstring resTypeW; if (pResName != nullptr) { resNameW.assign(pResName, pResName + strlen(pResName)); } if (pResType != nullptr) { resTypeW.assign(pResType, pResType + strlen(pResType)); } return FindResourceExW(hMod, pResType ? resTypeW.c_str() : nullptr, pResName ? resNameW.c_str() : nullptr, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); } MemoryBuffer *llvm::LoadBufferFromResource(const char *pResName, const char *pResType) { HMODULE hMod = NULL; // Get the handle to the current module GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)llvm::LoadBufferFromResource, &hMod); if (hMod == NULL) { return NULL; } // Locate the resource HRSRC hRes = FindResourceCompat(hMod, pResName, pResType); if (hRes == NULL) { return NULL; } // Load the resource HGLOBAL hBytes = LoadResource(hMod, hRes); if (hBytes == NULL) { return NULL; } // Get the base address to the resource. This call doesn't really lock it const char *pData = (char *)LockResource(hBytes); if (pData == NULL) { return NULL; } // Get the buffer size size_t dResSize = SizeofResource(hMod, hRes); if (dResSize == 0) { return NULL; } // this memory never needs to be freeded since it is not dynamically allocated return MemoryBuffer::getMemBuffer(StringRef(pData, dResSize), "", false).release(); } #endif // LLVM_ON_WIN32 MemoryBuffer* llvm::LoadBufferFromFile( const std::string &FileName ) { std::string FullFileName(FileName); // If buffer is not on the current working directory try to load it from // a predetermined path char *pEnv = getenv("INTEL_OPENCL_GPU_DIR"); FullFileName.insert(0, "Inc\\"); if (pEnv) { FullFileName.insert(0, "\\"); FullFileName.insert(0, pEnv); } ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(FullFileName); return FileOrErr.get().release(); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/LoadBuffer.h000066400000000000000000000031561363533017100243730ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "common/LLVMWarningsPush.hpp" #include #include "common/LLVMWarningsPop.hpp" #include namespace llvm { MemoryBuffer* LoadBufferFromResource(const char *pResName, const char *pResType); /// LoadBufferFromFile - Loads a buffer from a file in disk /// MemoryBuffer* LoadBufferFromFile( const std::string &FileName ); } // namespace llvm intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Patch/000077500000000000000000000000001363533017100232435ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Patch/patch_parser.cpp000066400000000000000000002202621363533017100264260ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include #include #include "../../3d/common/iStdLib/iStdLib.h" #include "IGC/common/igc_debug.h" #include "IGC/common/igc_regkeys.hpp" #include "patch_g7.h" #include "patch_g8.h" #include "patch_g9.h" #include "visa/include/RelocationInfo.h" #include "../sp/sp_debug.h" #include "Probe.h" namespace iOpenCL { void DebugProgramBinaryHeader( const iOpenCL::SProgramBinaryHeader* pHeader, std::string& output ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "Program Binary Header:\n" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMagic = %x\n", pHeader->Magic ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tVersion = %d\n", pHeader->Version ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDevice = %d\n", pHeader->Device ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tGPUPointerSizeInBytes = %d\n", pHeader->GPUPointerSizeInBytes ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tNumberOfKernels = %d\n", pHeader->NumberOfKernels ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSteppingId = %d\n", pHeader->SteppingId ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPatchListSize = %d\n", pHeader->PatchListSize ); } void DebugKernelBinaryHeader_Gen7( const iOpenCL::SKernelBinaryHeaderGen7* pHeader, std::string& output ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "Gen7 Kernel Binary Header:\n" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCheckSum = %x\n", pHeader->CheckSum ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tShaderHashCode = %" PRIu64 "\n", pHeader->ShaderHashCode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tKernelNameSize = %d\n", pHeader->KernelNameSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPatchListSize = %d\n", pHeader->PatchListSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tKernelHeapSize = %d\n", pHeader->KernelHeapSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tGeneralStateHeapSize = %d\n", pHeader->GeneralStateHeapSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDynamicStateHeapSize = %d\n", pHeader->DynamicStateHeapSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapSize = %d\n", pHeader->SurfaceStateHeapSize ); } void DebugPatchList( const void* pBuffer, const DWORD size, std::string& output ) { const BYTE* ptr = (const BYTE*)pBuffer; DWORD remaining = size; while( remaining ) { const iOpenCL::SPatchItemHeader* pHeader = (const iOpenCL::SPatchItemHeader*)ptr; if (IGC_IS_FLAG_ENABLED(DumpOCLProgramInfo)) { switch( pHeader->Token ) { // OpenCL Patch Tokens case iOpenCL::PATCH_TOKEN_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT: { const iOpenCL::SPatchGlobalMemoryObjectKernelArgument* pPatchItem = (const iOpenCL::SPatchGlobalMemoryObjectKernelArgument*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNumber = %d\n", pPatchItem->ArgumentNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); } break; case iOpenCL::PATCH_TOKEN_IMAGE_MEMORY_OBJECT_KERNEL_ARGUMENT: { const iOpenCL::SPatchImageMemoryObjectKernelArgument* pPatchItem = (const iOpenCL::SPatchImageMemoryObjectKernelArgument*)pHeader; const char* type = nullptr; switch( pPatchItem->Type ) { case iOpenCL::IMAGE_MEMORY_OBJECT_INVALID: type = "IMAGE_MEMORY_OBJECT_INVALID"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_BUFFER: type = "IMAGE_MEMORY_OBJECT_BUFFER"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_1D: type = "IMAGE_MEMORY_OBJECT_1D"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_1D_ARRAY: type = "IMAGE_MEMORY_OBJECT_1D_ARRAY"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D: type = "IMAGE_MEMORY_OBJECT_2D"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY: type = "IMAGE_MEMORY_OBJECT_2D_ARRAY"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_3D: type = "IMAGE_MEMORY_OBJECT_3D"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_CUBE: type = "IMAGE_MEMORY_OBJECT_CUBE"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_CUBE_ARRAY: type = "IMAGE_MEMORY_OBJECT_CUBE_ARRAY"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_DEPTH: type = "IMAGE_MEMORY_OBJECT_2D_DEPTH"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY_DEPTH: type = "IMAGE_MEMORY_OBJECT_2D_ARRAY_DEPTH"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_MSAA: type = "IMAGE_MEMORY_OBJECT_2D_MSAA"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_MSAA_DEPTH: type = "IMAGE_MEMORY_OBJECT_2D_MSAA_DEPTH"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY_MSAA: type = "IMAGE_MEMORY_OBJECT_2D_ARRAY_MSAA"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY_MSAA_DEPTH: type = "IMAGE_MEMORY_OBJECT_2D_ARRAY_MSAA_DEPTH"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_MEDIA: type = "IMAGE_MEMORY_OBJECT_2D_MEDIA"; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_MEDIA_BLOCK: type = "IMAGE_MEMORY_OBJECT_2D_MEDIA_BLOCK"; break; default: type = "Unknown"; IGC_ASSERT(0); break; }; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_IMAGE_MEMORY_OBJECT_KERNEL_ARGUMENT (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNumber = %d\n", pPatchItem->ArgumentNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = %s\n", type ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tLocationIndex1 = %d\n", pPatchItem->LocationIndex); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tLocationIndex2 = %d\n", pPatchItem->LocationIndex2); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tWriteable = %s\n", pPatchItem->Writeable ? "true" : "false" ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tTransformable = %s\n", pPatchItem->Transformable ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tNeedBindlessHandle = %s\n", pPatchItem->needBindlessHandle ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tIsEmulationArgument = %s\n", pPatchItem->IsEmulationArgument ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tbtiOffset = %d\n", pPatchItem->btiOffset); } break; case iOpenCL::PATCH_TOKEN_CONSTANT_MEMORY_OBJECT_KERNEL_ARGUMENT: { const iOpenCL::SPatchConstantMemoryObjectKernelArgument* pPatchItem = (const iOpenCL::SPatchConstantMemoryObjectKernelArgument*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_CONSTANT_MEMORY_OBJECT_KERNEL_ARGUMENT (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNumber = %d\n", pPatchItem->ArgumentNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tLocationIndex1 = %d\n", pPatchItem->LocationIndex); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tLocationIndex2 = %d\n", pPatchItem->LocationIndex2); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_WITH_INITIALIZATION: { const iOpenCL::SPatchAllocateGlobalMemorySurfaceWithInitialization* pPatchItem = (const iOpenCL::SPatchAllocateGlobalMemorySurfaceWithInitialization*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_WITH_INITIALIZATION (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tGlobalBufferIndex = %d\n", pPatchItem->GlobalBufferIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->Offset ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_WITH_INITIALIZATION: { const iOpenCL::SPatchAllocateConstantMemorySurfaceWithInitialization* pPatchItem = (const iOpenCL::SPatchAllocateConstantMemorySurfaceWithInitialization*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_WITH_INITIALIZATION (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantBufferIndex = %d\n", pPatchItem->ConstantBufferIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->Offset ); #if 0 // needed for CB2CR - need RT buy off. ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tInline CB Index = %d\n", pPatchItem->InlineConstantBufferIndex ); #endif } break; case iOpenCL::PATCH_TOKEN_SAMPLER_KERNEL_ARGUMENT: { const iOpenCL::SPatchSamplerKernelArgument* pPatchItem = (const iOpenCL::SPatchSamplerKernelArgument*)pHeader; const char* samplerType = nullptr; switch( pPatchItem->Type ) { case iOpenCL::SAMPLER_OBJECT_TEXTURE: samplerType = "Texture"; break; case iOpenCL::SAMPLER_OBJECT_SAMPLE_8X8_ERODE: samplerType = "Erode"; break; case iOpenCL::SAMPLER_OBJECT_SAMPLE_8X8_DILATE: samplerType = "Dilate"; break; case iOpenCL::SAMPLER_OBJECT_SAMPLE_8X8_MINMAXFILTER: samplerType = "MinMaxFilter"; break; case iOpenCL::SAMPLER_OBJECT_SAMPLE_8X8_2DCONVOLVE: samplerType = "2D Convolve"; break; case iOpenCL::SAMPLER_OBJECT_VME: samplerType = "VME"; break; case iOpenCL::SAMPLER_OBJECT_SAMPLE_8X8_MINMAX: samplerType = "MinMax"; break; case iOpenCL::SAMPLER_OBJECT_SAMPLE_8X8_CENTROID: samplerType = "Centroid"; break; case iOpenCL::SAMPLER_OBJECT_SAMPLE_8X8_BOOL_CENTROID: samplerType = "BoolCentroid"; break; case iOpenCL::SAMPLER_OBJECT_SAMPLE_8X8_BOOL_SUM: samplerType = "BoolSum"; break; default: samplerType = "Unknown"; break; }; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_SAMPLER_KERNEL_ARGUMENT (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNumber = %d\n", pPatchItem->ArgumentNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSamplerType = %s (%d)\n", samplerType, pPatchItem->Type ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tLocationIndex1 = %d\n", pPatchItem->LocationIndex); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tLocationIndex2 = %d\n", pPatchItem->LocationIndex2); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tNeedBindlessHandle = %s\n", pPatchItem->needBindlessHandle ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tIsEmulationArgument = %s\n", pPatchItem->IsEmulationArgument ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tbtiOffset = %d\n", pPatchItem->btiOffset); } break; case iOpenCL::PATCH_TOKEN_DATA_PARAMETER_BUFFER: { const iOpenCL::SPatchDataParameterBuffer* pPatchItem = (const iOpenCL::SPatchDataParameterBuffer*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_DATA_PARAMETER_BUFFER (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); switch( pPatchItem->Type ) { case iOpenCL::DATA_PARAMETER_KERNEL_ARGUMENT: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = KERNEL_ARGUMENT\n" ); break; case iOpenCL::DATA_PARAMETER_LOCAL_WORK_SIZE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = LOCAL_WORK_SIZE\n" ); break; case iOpenCL::DATA_PARAMETER_GLOBAL_WORK_SIZE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = GLOBAL_WORK_SIZE\n" ); break; case iOpenCL::DATA_PARAMETER_NUM_WORK_GROUPS: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = NUM_WORK_GROUPS\n" ); break; case iOpenCL::DATA_PARAMETER_WORK_DIMENSIONS: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = WORK_DIMENSIONS\n" ); break; case iOpenCL::DATA_PARAMETER_LOCAL_ID: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = LOCAL_ID\n" ); break; case iOpenCL::DATA_PARAMETER_EXECUTION_MASK: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = EXECUTION_MASK\n" ); break; case iOpenCL::DATA_PARAMETER_SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES\n" ); break; case iOpenCL::DATA_PARAMETER_IMAGE_WIDTH: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = IMAGE_WIDTH\n" ); break; case iOpenCL::DATA_PARAMETER_IMAGE_HEIGHT: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = IMAGE_HEIGHT\n" ); break; case iOpenCL::DATA_PARAMETER_IMAGE_DEPTH: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = IMAGE_DEPTH\n" ); break; case iOpenCL::DATA_PARAMETER_IMAGE_CHANNEL_DATA_TYPE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = IMAGE_CHANNEL_DATA_TYPE\n" ); break; case iOpenCL::DATA_PARAMETER_IMAGE_CHANNEL_ORDER: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = IMAGE_CHANNEL_ORDER\n" ); break; case iOpenCL::DATA_PARAMETER_IMAGE_ARRAY_SIZE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = IMAGE_ARRAY_SIZE\n" ); break; case iOpenCL::DATA_PARAMETER_SAMPLER_ADDRESS_MODE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = SAMPLER_ADDRESS_MODE\n" ); break; case iOpenCL::DATA_PARAMETER_SAMPLER_NORMALIZED_COORDS: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = SAMPLER_NORMALIZED_COORDS\n" ); break; case iOpenCL::DATA_PARAMETER_GLOBAL_WORK_OFFSET: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = GLOBAL_WORK_OFFSET\n" ); break; case iOpenCL::DATA_PARAMETER_NUM_HARDWARE_THREADS: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = NUM_HARDWARE_THREADS\n" ); break; case iOpenCL::DATA_PARAMETER_PRINTF_SURFACE_SIZE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = PRINTF_SURFACE_SIZE\n" ); break; case iOpenCL::DATA_PARAMETER_IMAGE_NUM_SAMPLES: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = IMAGE_NUM_SAMPLES\n" ); break; case iOpenCL::DATA_PARAMETER_SAMPLER_COORDINATE_SNAP_WA_REQUIRED: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = SAMPLER_COORDINATE_SNAP_WA_REQUIRED\n" ); break; case iOpenCL::DATA_PARAMETER_PARENT_EVENT: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = PARENT_EVENT\n" ); break; case iOpenCL::DATA_PARAMETER_MAX_WORKGROUP_SIZE: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = MAX_WORKGROUP_SIZE\n"); break; case iOpenCL::DATA_PARAMETER_PREFERRED_WORKGROUP_MULTIPLE: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = PREFERRED_WORKGROUP_MULTIPLE\n"); break; case iOpenCL::DATA_PARAMETER_VME_MB_BLOCK_TYPE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = VME_MB_BLOCK_TYPE\n" ); break; case iOpenCL::DATA_PARAMETER_VME_SUBPIXEL_MODE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = VME_SUBPIXEL_MODE\n" ); break; case iOpenCL::DATA_PARAMETER_VME_SAD_ADJUST_MODE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = VME_SAD_ADJUST_MODE\n" ); break; case iOpenCL::DATA_PARAMETER_VME_SEARCH_PATH_TYPE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = VME_SEARCH_PATH_TYPE\n" ); break; case iOpenCL::DATA_PARAMETER_IMAGE_NUM_MIP_LEVELS: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = IMAGE_NUM_MIP_LEVELS\n" ); break; case iOpenCL::DATA_PARAMETER_ENQUEUED_LOCAL_WORK_SIZE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = ENQUEUED_LOCAL_WORK_SIZE\n" ); break; case iOpenCL::DATA_PARAMETER_LOCAL_MEMORY_STATELESS_WINDOW_START_ADDRESS: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = LOCAL_MEMORY_STATELESS_WINDOW_START_ADDRESS\n" ); break; case iOpenCL::DATA_PARAMETER_LOCAL_MEMORY_STATELESS_WINDOW_SIZE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = LOCAL_MEMORY_STATELESS_WINDOW_SIZE\n" ); break; case iOpenCL::DATA_PARAMETER_PRIVATE_MEMORY_STATELESS_SIZE: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = PRIVATE_MEMORY_STATELESS_SIZE\n" ); break; case iOpenCL::DATA_PARAMETER_OBJECT_ID: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = OBJECT_ID\n"); break; case iOpenCL::DATA_PARAMETER_SIMD_SIZE: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = SIMD_SIZE\n"); break; case iOpenCL::DATA_PARAMETER_CHILD_BLOCK_SIMD_SIZE: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = CHILD_BLOCK_SIMD_SIZE\n"); break; case iOpenCL::DATA_PARAMETER_STAGE_IN_GRID_ORIGIN: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = STAGE_IN_GRID_ORIGIN\n"); break; case iOpenCL::DATA_PARAMETER_STAGE_IN_GRID_SIZE: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = STAGE_IN_GRID_SIZE\n"); break; case iOpenCL::DATA_PARAMETER_BUFFER_OFFSET: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = BUFFER_OFFSET\n"); break; case iOpenCL::DATA_PARAMETER_BUFFER_STATEFUL: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = BUFFER_STATEFUL\n"); break; case iOpenCL::DATA_PARAMETER_FLAT_IMAGE_BASEOFFSET: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = FLAT_IMAGE_BASEOFFSET\n"); break; case iOpenCL::DATA_PARAMETER_FLAT_IMAGE_HEIGHT: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = FLAT_IMAGE_HEIGHT\n"); break; case iOpenCL::DATA_PARAMETER_FLAT_IMAGE_WIDTH: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = FLAT_IMAGE_WIDTH\n"); break; case iOpenCL::DATA_PARAMETER_FLAT_IMAGE_PITCH: ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tType = FLAT_IMAGE_PITCH\n"); break; default: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = UNKNOWN_TYPE\n" ); break; } ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNumber = %d\n", pPatchItem->ArgumentNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataSize = %d\n", pPatchItem->DataSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSourceOffset = %d\n", pPatchItem->SourceOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLocationIndex1 = %d\n", pPatchItem->LocationIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLocationIndex2 = %d\n", pPatchItem->LocationIndex2 ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tIsEmulationArgument = %s\n", pPatchItem->IsEmulationArgument ? "true" : "false"); } break; // Gen5.75 and Gen6 Allocation Tokens case iOpenCL::PATCH_TOKEN_ALLOCATE_LOCAL_SURFACE: { const iOpenCL::SPatchAllocateLocalSurface* pPatchItem = ( const iOpenCL::SPatchAllocateLocalSurface* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_LOCAL_SURFACE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTotalInlineLocalMemorySize = %d\n", pPatchItem->TotalInlineLocalMemorySize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_SCRATCH_SURFACE: { const iOpenCL::SPatchAllocateScratchSurface* pPatchItem = ( const iOpenCL::SPatchAllocateScratchSurface* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_SCRATCH_SURFACE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPerThreadScratchSpaceSize = %d\n", pPatchItem->PerThreadScratchSpaceSize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_PRIVATE_MEMORY: { const iOpenCL::SPatchAllocatePrivateMemorySurface* pPatchItem = ( const iOpenCL::SPatchAllocatePrivateMemorySurface* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_PRIVATE_MEMORY (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPerThreadPrivateMemorySize = %d\n", pPatchItem->PerThreadPrivateMemorySize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_SIP_SURFACE: { const iOpenCL::SPatchAllocateSystemThreadSurface* pPatchItem = ( const iOpenCL::SPatchAllocateSystemThreadSurface* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_SIP_SURFACE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPerThreadSystemThreadSurfaceSize = %d\n", pPatchItem->PerThreadSystemThreadSurfaceSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBTI = %d\n", pPatchItem->BTI ); } break; // Gen5.75 and Gen6 State Programming case iOpenCL::PATCH_TOKEN_STATE_SIP: { const iOpenCL::SPatchStateSIP* pPatchItem = (const iOpenCL::SPatchStateSIP*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_STATE_SIP (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSystemKernelOffset = %d\n", pPatchItem->SystemKernelOffset ); } break; case iOpenCL::PATCH_TOKEN_SAMPLER_STATE_ARRAY: { const iOpenCL::SPatchSamplerStateArray* pPatchItem = (const iOpenCL::SPatchSamplerStateArray*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_SAMPLER_STATE_ARRAY (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCount = %d\n", pPatchItem->Count ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBorderColorOffset = %d\n", pPatchItem->BorderColorOffset ); } break; case iOpenCL::PATCH_TOKEN_BINDING_TABLE_STATE: { const iOpenCL::SPatchBindingTableState* pPatchItem = (const iOpenCL::SPatchBindingTableState*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_BINDING_TABLE_STATE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCount = %d\n", pPatchItem->Count ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateOffset = %d\n", pPatchItem->SurfaceStateOffset ); } break; // Gen6 State Programming case iOpenCL::PATCH_TOKEN_MEDIA_VFE_STATE: { const iOpenCL::SPatchMediaVFEState* pPatchItem = (const iOpenCL::SPatchMediaVFEState*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_MEDIA_VFE_STATE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tScratchSpaceOffset = %d\n", pPatchItem->ScratchSpaceOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPerThreadScratchSpace = %d\n", pPatchItem->PerThreadScratchSpace ); } break; case iOpenCL::PATCH_TOKEN_MEDIA_VFE_STATE_SLOT1: { const iOpenCL::SPatchMediaVFEState* pPatchItem = (const iOpenCL::SPatchMediaVFEState*)pHeader; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "PATCH_TOKEN_MEDIA_VFE_STATE_SLOT1 (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tScratchSpaceOffset = %d\n", pPatchItem->ScratchSpaceOffset); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tPerThreadScratchSpaceSlot1 = %d\n", pPatchItem->PerThreadScratchSpace); } break; case iOpenCL::PATCH_TOKEN_MEDIA_INTERFACE_DESCRIPTOR_LOAD: { const iOpenCL::SPatchMediaInterfaceDescriptorLoad* pPatchItem = (const iOpenCL::SPatchMediaInterfaceDescriptorLoad*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_MEDIA_INTERFACE_DESCRIPTOR_LOAD (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tInterfaceDescriptorDataOffset = %d\n", pPatchItem->InterfaceDescriptorDataOffset ); } break; case iOpenCL::PATCH_TOKEN_INTERFACE_DESCRIPTOR_DATA: { const iOpenCL::SPatchInterfaceDescriptorData* pPatchItem = (const iOpenCL::SPatchInterfaceDescriptorData*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_INTERFACE_DESCRIPTOR_DATA (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSamplerStateOffset = %d\n", pPatchItem->SamplerStateOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tKernelOffset = %d\n", pPatchItem->KernelOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBindingTableOffset = %d\n", pPatchItem->BindingTableOffset); } break; case iOpenCL::PATCH_TOKEN_THREAD_PAYLOAD: { const iOpenCL::SPatchThreadPayload* pPatchItem = (const iOpenCL::SPatchThreadPayload*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_THREAD_PAYLOAD (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tHeaderPresent = %s\n", pPatchItem->HeaderPresent ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLocalIDXPresent = %s\n", pPatchItem->LocalIDXPresent ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLocalIDYPresent = %s\n", pPatchItem->LocalIDYPresent ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLocalIDZPresent = %s\n", pPatchItem->LocalIDZPresent ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLocalIDFlattenedPresent = %s\n", pPatchItem->LocalIDFlattenedPresent ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tIndirectPayloadStorage = %s\n", pPatchItem->IndirectPayloadStorage ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tUnusedPerThreadConstantPresent = %s\n", pPatchItem->UnusedPerThreadConstantPresent ? "true" : "false" ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tGetLocalIDPresent = %s\n", pPatchItem->GetLocalIDPresent ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tGetGlobalOffsetPresent = %s\n", pPatchItem->GetGlobalOffsetPresent ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tGetGroupIDPresent = %s\n", pPatchItem->GetGroupIDPresent ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tStageInGridOriginPresent = %s\n", pPatchItem->StageInGridOriginPresent ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tStageInGridSizePresent = %s\n", pPatchItem->StageInGridSizePresent ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tOffsetToSkipPerThreadDataLoad = %d\n", pPatchItem->OffsetToSkipPerThreadDataLoad); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tOffsetToSkipSetFFIDGP = %d\n", pPatchItem->OffsetToSkipSetFFIDGP); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tPassInlineData = %s\n", pPatchItem->PassInlineData ? "true" : "false"); } break; case iOpenCL::PATCH_TOKEN_EXECUTION_ENVIRONMENT: { const iOpenCL::SPatchExecutionEnvironment* pPatchItem = (const iOpenCL::SPatchExecutionEnvironment*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_EXECUTION_ENVIRONMENT (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRequiredWorkGroupSizeX = %d\n", pPatchItem->RequiredWorkGroupSizeX ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRequiredWorkGroupSizeY = %d\n", pPatchItem->RequiredWorkGroupSizeY ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRequiredWorkGroupSizeZ = %d\n", pPatchItem->RequiredWorkGroupSizeZ ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLargestCompiledSIMDSize = %d\n", pPatchItem->LargestCompiledSIMDSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tHasBarriers = %s\n", pPatchItem->HasBarriers ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDisableMidThreadPreemption = %s\n", pPatchItem->DisableMidThreadPreemption ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCompiledSIMD8 = %s\n", pPatchItem->CompiledSIMD8 ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCompiledSIMD16 = %s\n", pPatchItem->CompiledSIMD16 ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCompiledSIMD32 = %s\n", pPatchItem->CompiledSIMD32 ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tHasDeviceEnqueue = %s\n", pPatchItem->HasDeviceEnqueue ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMayAccessUndeclaredResource = %s\n", pPatchItem->MayAccessUndeclaredResource ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tUsesFencesForReadWriteImages = %s\n", pPatchItem->UsesFencesForReadWriteImages ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tUsesStatelessSpillFill = %s\n", pPatchItem->UsesStatelessSpillFill ? "true" : "false" ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tUsesMultiScratchSpaces = %s\n", pPatchItem->UsesMultiScratchSpaces ? "true" : "false"); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tIsCoherent = %s\n", pPatchItem->IsCoherent ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSubgroupIndependentForwardProgressRequired = %s\n", pPatchItem->SubgroupIndependentForwardProgressRequired ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCompiledSubGroupsNumber = %d\n", pPatchItem->CompiledSubGroupsNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCompiledForGreaterThan4GBBuffers = %s\n", pPatchItem->CompiledForGreaterThan4GBBuffers ? "true" : "false" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tHasGlobalAtomics = %s\n", pPatchItem->HasGlobalAtomics ? "true" : "false"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tNumGRFRequired = %d\n", pPatchItem->NumGRFRequired); } break; case iOpenCL::PATCH_TOKEN_DATA_PARAMETER_STREAM: { const iOpenCL::SPatchDataParameterStream* pPatchItem = (const iOpenCL::SPatchDataParameterStream*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_DATA_PARAMETER_STREAM (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParameterStreamSize = %d\n", pPatchItem->DataParameterStreamSize); } break; case iOpenCL::PATCH_TOKEN_KERNEL_ATTRIBUTES_INFO: { const iOpenCL::SPatchKernelAttributesInfo* pPatchItem = (const iOpenCL::SPatchKernelAttributesInfo*)pHeader; char* pStr = (char*)pHeader + sizeof(iOpenCL::SPatchKernelAttributesInfo); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_KERNEL_ATTRIBUTES_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAttributeSize = %3d | value = \"%s\"\n", pPatchItem->AttributesSize, pStr ); } break; case iOpenCL::PATCH_TOKEN_KERNEL_ARGUMENT_INFO: { const iOpenCL::SPatchKernelArgumentInfo* pPatchItem = (const iOpenCL::SPatchKernelArgumentInfo*)pHeader; char* pStr = (char*)pHeader + sizeof(iOpenCL::SPatchKernelArgumentInfo); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_KERNEL_ARGUMENT_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNumber = %3d\n", pPatchItem->ArgumentNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAddressQualifierSize = %3d | value = \"%s\"\n", pPatchItem->AddressQualifierSize, pStr ); pStr += pPatchItem->AddressQualifierSize; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAccessQualifierSize = %3d | value = \"%s\"\n", pPatchItem->AccessQualifierSize, pStr ); pStr += pPatchItem->AccessQualifierSize; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNameSize = %3d | value = \"%s\"\n", pPatchItem->ArgumentNameSize, pStr ); pStr += pPatchItem->ArgumentNameSize; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTypeNameSize = %3d | value = \"%s\"\n", pPatchItem->TypeNameSize, pStr ); pStr += pPatchItem->TypeNameSize; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTypeQualifierSize = %3d | value = \"%s\"\n", pPatchItem->TypeQualifierSize, pStr ); pStr += pPatchItem->TypeQualifierSize; } break; case iOpenCL::PATCH_TOKEN_STRING: { const iOpenCL::SPatchString* pPatchItem = (const iOpenCL::SPatchString*)pHeader; char* pStr = (char*)pHeader + sizeof(iOpenCL::SPatchString); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_STRING (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tString Index = %d\n", pPatchItem->Index); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tString Size = %d | value = \"%s\"\n", pPatchItem->StringSize, pStr ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_PRINTF_SURFACE: { const iOpenCL::SPatchAllocatePrintfSurface* pPatchItem = ( const iOpenCL::SPatchAllocatePrintfSurface* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_PRINTF_SURFACE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPrintfSurfaceIndex = %d\n", pPatchItem->PrintfSurfaceIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_SYNC_BUFFER: { const iOpenCL::SPatchAllocateSyncBuffer* pPatchItem = (const iOpenCL::SPatchAllocateSyncBuffer*)pHeader; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_SYNC_BUFFER (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize); } break; // Stateless Tokens case iOpenCL::PATCH_TOKEN_STATELESS_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT: { const iOpenCL::SPatchStatelessGlobalMemoryObjectKernelArgument* pPatchItem = (const iOpenCL::SPatchStatelessGlobalMemoryObjectKernelArgument*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_STATELESS_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNumber = %d\n", pPatchItem->ArgumentNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tLocationIndex = %d\n", pPatchItem->LocationIndex); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tLocationIndex2 = %d\n", pPatchItem->LocationIndex2); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tIsEmulationArgument = %s\n", pPatchItem->IsEmulationArgument ? "true" : "false"); } break; case iOpenCL::PATCH_TOKEN_STATELESS_CONSTANT_MEMORY_OBJECT_KERNEL_ARGUMENT: { const iOpenCL::SPatchStatelessConstantMemoryObjectKernelArgument* pPatchItem = (const iOpenCL::SPatchStatelessConstantMemoryObjectKernelArgument*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_STATELESS_CONSTANT_MEMORY_OBJECT_KERNEL_ARGUMENT (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tArgumentNumber = %d\n", pPatchItem->ArgumentNumber ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize ); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tIsEmulationArgument = %s\n", pPatchItem->IsEmulationArgument ? "true" : "false"); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_GLOBAL_MEMORY_SURFACE_WITH_INITIALIZATION: { const iOpenCL::SPatchAllocateStatelessGlobalMemorySurfaceWithInitialization* pPatchItem = (const iOpenCL::SPatchAllocateStatelessGlobalMemorySurfaceWithInitialization*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_STATELESS_GLOBAL_MEMORY_SURFACE_WITH_INITIALIZATION (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tIndex = %d\n", pPatchItem->GlobalBufferIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_CONSTANT_MEMORY_SURFACE_WITH_INITIALIZATION: { const iOpenCL::SPatchAllocateStatelessConstantMemorySurfaceWithInitialization* pPatchItem = (const iOpenCL::SPatchAllocateStatelessConstantMemorySurfaceWithInitialization*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_STATELESS_CONSTANT_MEMORY_SURFACE_WITH_INITIALIZATION (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tIndex = %d\n", pPatchItem->ConstantBufferIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_PRINTF_SURFACE: { const iOpenCL::SPatchAllocateStatelessPrintfSurface* pPatchItem = (const iOpenCL::SPatchAllocateStatelessPrintfSurface*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_STATELESS_PRINTF_SURFACE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPrintfSurfaceIndex = %d\n", pPatchItem->PrintfSurfaceIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_PRIVATE_MEMORY: { const iOpenCL::SPatchAllocateStatelessPrivateSurface* pPatchItem = (const iOpenCL::SPatchAllocateStatelessPrivateSurface*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_STATELESS_PRIVATE_MEMORY (%08X) (size = %d )\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tPerThreadPrivateMemorySize= %d\n", pPatchItem->PerThreadPrivateMemorySize ); } break; case iOpenCL::PATCH_TOKEN_CB_MAPPING: { const iOpenCL::SPatchConstantBufferMapping* pPatchItem = ( const iOpenCL::SPatchConstantBufferMapping* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_CB_MAPPING (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantBuffeType = %s (%d)\n", pPatchItem->ConstantBufferType == iOpenCL::CONSTANT_BUFFER_TYPE_KERNEL_ARGUMENT ? "CONSTANT_BUFFER_TYPE_KERNEL_ARGUMENT" : "CONSTANT_BUFFER_TYPE_INLINE", pPatchItem->ConstantBufferType ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantBufferIndex = %d\n", pPatchItem->ConstantBufferIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantBufferId = %d\n", pPatchItem->ConstantBufferId ); } break; case iOpenCL::PATCH_TOKEN_CB2CR_GATHER_TABLE: { #if 0 const iOpenCL::SPatchCB2CRGatherTable* pPatchItem = ( const iOpenCL::SPatchCB2CRGatherTable* )pHeader; const USC::SConstantGatherEntry* pTable = ( const USC::SConstantGatherEntry* )( pPatchItem + 1 ); DWORD i = 0; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_CB2CR_GATHER_TABLE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tNumberOfEntries = %d\n", pPatchItem->NumberOfEntries ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); for( i = 0; i < pPatchItem->NumberOfEntries; i++ ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tEntry Number: %d\n", i ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\t\tConstantBufferIndex = %d\n", pTable[i].GatherEntry.Fields.constantBufferIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\t\tChannelMask = 0x%X\n", pTable[i].GatherEntry.Fields.channelMask ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\t\tConstantBufferOffset = %d\n", pTable[i].GatherEntry.Fields.constantBufferOffset ); } #endif } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_EVENT_POOL_SURFACE: { const iOpenCL::SPatchAllocateStatelessEventPoolSurface* pPatchItem = ( const iOpenCL::SPatchAllocateStatelessEventPoolSurface* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_STATELESS_EVENT_POOL_SURFACE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tEventPooolSurfaceIndex = %d\n", pPatchItem->EventPoolSurfaceIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_DEFAULT_DEVICE_QUEUE_SURFACE: { const iOpenCL::SPatchAllocateStatelessDefaultDeviceQueueSurface* pPatchItem = (const iOpenCL::SPatchAllocateStatelessDefaultDeviceQueueSurface*)pHeader; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_STATELESS_DEFAULT_DEVICE_QUEUE_SURFACE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize); } break; case iOpenCL::PATCH_TOKEN_STATELESS_DEVICE_QUEUE_KERNEL_ARGUMENT: { const iOpenCL::SPatchStatelessDeviceQueueKernelArgument* pPatchItem = (const iOpenCL::SPatchStatelessDeviceQueueKernelArgument*)pHeader; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "PATCH_TOKEN_STATELESS_DEVICE_QUEUE_KERNEL_ARGUMENT (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tArgumentNumber = %d\n", pPatchItem->ArgumentNumber); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tSurfaceStateHeapOffset = %d\n", pPatchItem->SurfaceStateHeapOffset); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tDataParamOffset = %d\n", pPatchItem->DataParamOffset); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tDataParamSize = %d\n", pPatchItem->DataParamSize); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tIsEmulationArgument = %s\n", pPatchItem->IsEmulationArgument ? "true" : "false"); } break; case iOpenCL::PATCH_TOKEN_NULL_SURFACE_LOCATION: { const iOpenCL::SPatchNullSurfaceLocation* pPatchItem = ( const iOpenCL::SPatchNullSurfaceLocation* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_NULL_SURFACE_LOCATION (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tOffset = %d\n", pPatchItem->Offset ); } break; case iOpenCL::PATCH_TOKEN_CONSTRUCTOR_DESTRUCTOR_KERNEL_PROGRAM_BINARY_INFO: { const iOpenCL::SPatchKernelTypeProgramBinaryInfo* pPatchItem = (const iOpenCL::SPatchKernelTypeProgramBinaryInfo*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_CONSTRUCTOR_DESTRUCTOR_KERNEL_PROGRAM_BINARY_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); char* kType; if (pPatchItem->Type) kType = "Destructor"; else kType = "Constructor"; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tType = %s\n", kType); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tInitializationDataSize = %d\n", pPatchItem->InlineDataSize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_PROGRAM_BINARY_INFO: { const iOpenCL::SPatchAllocateConstantMemorySurfaceProgramBinaryInfo* pPatchItem = (const iOpenCL::SPatchAllocateConstantMemorySurfaceProgramBinaryInfo*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_PROGRAM_BINARY_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBufferIndex = %d\n", pPatchItem->ConstantBufferIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tInitializationDataSize = %d\n", pPatchItem->InlineDataSize ); } break; case iOpenCL::PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_PROGRAM_BINARY_INFO: { const iOpenCL::SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo* pPatchItem = (const iOpenCL::SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_PROGRAM_BINARY_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBufferType = %d\n", pPatchItem->Type ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBufferIndex = %d\n", pPatchItem->GlobalBufferIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tInitializationDataSize = %d\n", pPatchItem->InlineDataSize ); } break; case iOpenCL::PATCH_TOKEN_GLOBAL_POINTER_PROGRAM_BINARY_INFO: { const iOpenCL::SPatchGlobalPointerProgramBinaryInfo* pPatchItem = (const iOpenCL::SPatchGlobalPointerProgramBinaryInfo*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_GLOBAL_POINTER_PROGRAM_BINARY_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tGlobalBufferIndex = %d\n", pPatchItem->GlobalBufferIndex); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tGlobalPointerOffset = %" PRIu64 "\n", pPatchItem->GlobalPointerOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBufferType = %d\n", pPatchItem->BufferType); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBufferIndex = %d\n", pPatchItem->BufferIndex); } break; case iOpenCL::PATCH_TOKEN_CONSTANT_POINTER_PROGRAM_BINARY_INFO: { const iOpenCL::SPatchConstantPointerProgramBinaryInfo* pPatchItem = (const iOpenCL::SPatchConstantPointerProgramBinaryInfo*)pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_CONSTANT_POINTER_PROGRAM_BINARY_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantBufferIndex = %d\n", pPatchItem->ConstantBufferIndex); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantPointerOffset = %" PRIu64 "\n", pPatchItem->ConstantPointerOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBufferType = %d\n", pPatchItem->BufferType); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBufferIndex = %d\n", pPatchItem->BufferIndex); } break; case iOpenCL::PATCH_TOKEN_INLINE_VME_SAMPLER_INFO: { const iOpenCL::SPatchInlineVMESamplerInfo* pPatchItem = ( const iOpenCL::SPatchInlineVMESamplerInfo* )pHeader; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "PATCH_TOKEN_INLINE_VME_SAMPLER_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size ); } break; case iOpenCL::PATCH_TOKEN_GTPIN_FREE_GRF_INFO: { const iOpenCL::SPatchGtpinFreeGRFInfo* pPatchItem = (const iOpenCL::SPatchGtpinFreeGRFInfo*)pHeader; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "PATCH_TOKEN_GTPIN_FREE_GRF_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tBufferSize = %d\n", pPatchItem->BufferSize); } break; case iOpenCL::PATCH_TOKEN_GTPIN_INFO: { const iOpenCL::SPatchItemHeader* pPatchItem = pHeader; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "PATCH_TOKEN_GTPIN_INFO (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size); } break; case iOpenCL::PATCH_TOKEN_PROGRAM_SYMBOL_TABLE: { const iOpenCL::SPatchFunctionTableInfo* pPatchItem = (const iOpenCL::SPatchFunctionTableInfo*)pHeader; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "PATCH_TOKEN_PROGRAM_SYMBOL_TABLE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tNumEntries = %d\n", pPatchItem->NumEntries); vISA::GenSymEntry* entryPtr = (vISA::GenSymEntry*) (ptr + sizeof(iOpenCL::SPatchFunctionTableInfo)); for (unsigned i = 0; i < pPatchItem->NumEntries; i++) { ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tSymbol(Entry %02d): %s\n\t Offset = %d\n\t Size = %d\n\t Type = %d\n", i, entryPtr->s_name, entryPtr->s_offset, entryPtr->s_size, entryPtr->s_type); entryPtr++; } } break; case iOpenCL::PATCH_TOKEN_PROGRAM_RELOCATION_TABLE: { const iOpenCL::SPatchFunctionTableInfo* pPatchItem = (const iOpenCL::SPatchFunctionTableInfo*)pHeader; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "PATCH_TOKEN_PROGRAM_RELOCATION_TABLE (%08X) (size = %d)\n", pPatchItem->Token, pPatchItem->Size); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tNumEntries = %d\n", pPatchItem->NumEntries); vISA::GenRelocEntry* entryPtr = (vISA::GenRelocEntry*) (ptr + sizeof(iOpenCL::SPatchFunctionTableInfo)); for (unsigned i = 0; i < pPatchItem->NumEntries; i++) { ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\tRelocSymbol(Entry %02d): %s\n\t Offset = %d\n\t Type = %d\n", i, entryPtr->r_symbol, entryPtr->r_offset, entryPtr->r_type); entryPtr++; } } break; default: { IGC_ASSERT(0); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "*** UNKNOWN TOKEN %08X (size = %d)***\n", pHeader->Token, pHeader->Size ); } break; } } ptr += pHeader->Size; remaining -= pHeader->Size; } } } // namespace intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Patch/patch_parser.h000066400000000000000000000033111363533017100260650ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once namespace iOpenCL { struct SProgramBinaryHeader; struct SKernelBinaryHeaderGen7; void DebugProgramBinaryHeader( const iOpenCL::SProgramBinaryHeader* pHeader, std::string& output ); void DebugKernelBinaryHeader_Gen7( const iOpenCL::SKernelBinaryHeaderGen7* pHeader, std::string& output ); void DebugPatchList( const void* pPatchList, const DWORD size, std::string& output ); } // namespace intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/000077500000000000000000000000001363533017100237705ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_3d_def_g8.h000066400000000000000000000151611363533017100265120ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_3d_enum_g6.h" // Set packing alignment to a single byte #pragma pack(1) namespace G6HWC { /*****************************************************************************\ STRUCT: S3DPipeControl (PIPE_CONTROL) \*****************************************************************************/ struct S3DPipeControl { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE( 0, 7 ); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE( 8, 15 ); DWORD InstructionSubOpcode : BITFIELD_RANGE( 16, 23 ); // GFX3DCONTROL_SUBOPCODE DWORD InstructionOpcode : BITFIELD_RANGE( 24, 26 ); // GFX3D_OPCODE:PIPE_CONTROL DWORD InstructionSubType : BITFIELD_RANGE( 27, 28 ); // INSTRUCTION_SUBTYPE DWORD InstructionType : BITFIELD_RANGE( 29, 31 ); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD DepthCacheFlushEnable : BITFIELD_BIT( 0 ); // bool DWORD StallAtPixelScoreboardEnable : BITFIELD_BIT( 1 ); // bool DWORD StateCacheInvalidationEnable : BITFIELD_BIT( 2 ); // bool DWORD ConstantCacheInvalidationEnable : BITFIELD_BIT( 3 ); // bool DWORD VertexFetchCacheInvalidationEnable : BITFIELD_BIT( 4 ); // bool DWORD _Unused1 : BITFIELD_BIT( 5 ); // Reserved DWORD ProtectedMemoryApplicationId : BITFIELD_BIT( 6 ); // bool DWORD _Unused2 : BITFIELD_BIT( 7 ); // Reserved DWORD NotifyEnable : BITFIELD_BIT( 8 ); // bool DWORD IndirectStatePointersDisable : BITFIELD_BIT( 9 ); // bool DWORD TextureCacheInvalidationEnable : BITFIELD_BIT( 10 ); // bool DWORD InstructionCacheInvalidationEnable : BITFIELD_BIT( 11 ); // bool DWORD RenderTargetCacheFlushEnable : BITFIELD_BIT( 12 ); // bool DWORD DepthStallEnable : BITFIELD_BIT( 13 ); // bool DWORD PostSyncOperation : BITFIELD_RANGE( 14, 15 ); // GFX3DCONTROL_OPERATION DWORD MediaPrtComplete : BITFIELD_BIT( 16 ); // bool DWORD SynchronizeGfdtSurfaceEnable : BITFIELD_BIT( 17 ); // bool DWORD TlbInvalidateEnable : BITFIELD_BIT( 18 ); // bool DWORD GlobalSnapshotCountReset : BITFIELD_BIT( 19 ); // bool DWORD CommandStreamStallEnable : BITFIELD_BIT( 20 ); // bool DWORD StoreDataIndexEnable : BITFIELD_BIT( 21 ); // bool DWORD ProtectedMemoryEnable : BITFIELD_BIT( 22 ); // bool DWORD _Unused3 : BITFIELD_RANGE( 23, 31 ); } All; struct _Gen7 { DWORD DCFlushEnable : BITFIELD_BIT( 5 ); // bool DWORD PipeControlFlushEnable : BITFIELD_BIT( 7 ); // bool DWORD _Unused : BITFIELD_BIT( 17 ); // Reserved DWORD LRIPostSyncOperation : BITFIELD_BIT( 23 ); // U1 DWORD DestinationAddressType : BITFIELD_BIT( 24 ); // U1 } Gen7; struct _Gen7_5 { DWORD CoreModeEnable : BITFIELD_BIT( 25 ); // bool } Gen7_5; struct _Gen8 { DWORD ProtectedModeDisable : BITFIELD_BIT( 27 ); // bool } Gen8; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD _Unused : BITFIELD_RANGE( 0, 1 ); DWORD DestinationAddressType : BITFIELD_BIT( 2 ); // GFX3DCONTROL_GTTWRITE_MODE DWORD DestinationAddress : BITFIELD_RANGE( 3, 31 ); // GTT[31:3] } All; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD Data; } All; struct _Gen8 { DWORD Destination64bitAddress : BITFIELD_RANGE( 0, 15 ); // GTT[47:32] DWORD _Unused : BITFIELD_RANGE( 16, 31 ); // Reserved } Gen8; DWORD Value; } DW3; union _DW4 { struct _All { DWORD Data; } All; DWORD Value; } DW4; union _DW5 { struct _All { DWORD Data; } All; DWORD Value; } DW5; }; static_assert(SIZE32(S3DPipeControl) == 6); } // namespace G6HWC // Reset packing alignment to project default #pragma pack() intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_3d_enum_g8.h000066400000000000000000000060641363533017100267220ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_enum_g8.h" namespace G6HWC { /*****************************************************************************\ ENUM: GFX3D_OPCODE \*****************************************************************************/ enum GFX3D_OPCODE { GFX3DOP_3DSTATE_PIPELINED = 0x0, GFX3DOP_3DSTATE_NONPIPELINED = 0x1, GFX3DOP_PIPECONTROL = 0x2, GFX3DOP_3DPRIMITIVE = 0x3 }; /*****************************************************************************\ ENUM: GFX3DCONTROL_GTTWRITE_MODE \*****************************************************************************/ enum GFX3DCONTROL_GTTWRITE_MODE { GFX3DCONTROL_GTTWRITE_PROCESS_LOCAL = 0x00, GFX3DCONTROL_GTTWRITE_GLOBAL = 0x01 }; /*****************************************************************************\ ENUM: GFX3DCONTROL_SUBOPCODE \*****************************************************************************/ enum GFX3DCONTROL_SUBOPCODE { GFX3DSUBOP_3DCONTROL = 0x00 }; /*****************************************************************************\ ENUM: GFX3DCONTROL_OPERATION \*****************************************************************************/ enum GFX3DCONTROL_OPERATION { GFX3DCONTROLOP_NOWRITE = 0x00, GFX3DCONTROLOP_WRITEIMMEDIATE = 0x01, GFX3DCONTROLOP_WRITEDEPTH = 0x02, GFX3DCONTROLOP_WRITETIMESTAMP = 0x03 }; /*****************************************************************************\ ENUM: GFX3DSTATE_ROUNDING_MODE \*****************************************************************************/ enum GFX3DSTATE_ROUNDING_MODE { GFX3DSTATE_ROUNDING_MODE_ROUND_TO_NEAREST_EVEN = 0x0, GFX3DSTATE_ROUNDING_MODE_ROUND_TO_POS_INF = 0x1, GFX3DSTATE_ROUNDING_MODE_ROUND_TO_NEG_INF = 0x2, GFX3DSTATE_ROUNDING_MODE_ROUND_TO_ZERO = 0x3 }; } // namespace G6HWCintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_3d_init_g8.h000066400000000000000000000106751363533017100267240ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_3d_enum_g6.h" #include "cmd_3d_def_g6.h" namespace G6HWC { /*****************************************************************************\ CONST: g_cInit3DPipeControl \*****************************************************************************/ static const S3DPipeControl g_cInit3DPipeControl = { // DWORD 0 { OP_LENGTH( SIZE32( S3DPipeControl ) ), // Length 0, // _Unused GFX3DSUBOP_3DCONTROL, // InstructionSubOpcode GFX3DOP_PIPECONTROL, // InstructionOpcode PIPE_3D, // InstructionSubType INSTRUCTION_GFX // InstructionType }, // DWORD 1 { false, // DepthCacheFlushInhibitEnable false, // StallAtPixelScoreboardEnable false, // StateCacheInvalidationEnable false, // ConstantCacheInvalidationEnable false, // VertexFetchCacheInvalidationEnable 0, // _Unused1 false, // ProtectedMemoryApplicationId 0, // _Unused2 false, // NotifyEnable false, // IndirectStatePointersDisable false, // TextureCacheInvalidationEnable false, // InstructionCacheInvalidationEnable false, // RenderTargetCacheFlushEnable false, // DepthStallEnable GFX3DCONTROLOP_NOWRITE, // PostSyncOperation false, // MediaPrtComplete false, // SynchronizeGfdtSurfaceEnable false, // TlbInvalidateEnable false, // GlobalSnapshotCountReset false, // CommandStreamStallEnable false, // StoreDataIndexEnable false, // ProtectedMemoryEnable 0, // _Unused3 }, // DWORD 2 { 0, // _Unused GFX3DCONTROL_GTTWRITE_GLOBAL, // DestinationAddressType 0 // DestinationAddress }, // DWORD 3 { 0 // ImmediateData }, // DWORD 4 { 0 // ImmediateData }, // DWORD 5 { 0 // ImmediateData } }; } // namespace G6HWC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_enum.h000066400000000000000000000043511363533017100257330ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once /*****************************************************************************\ MACRO: SIZE16 \*****************************************************************************/ #ifndef SIZE16 #define SIZE16( x ) ((DWORD)( sizeof(x) / sizeof(WORD) )) #endif /*****************************************************************************\ MACRO: SIZE32 \*****************************************************************************/ #ifndef SIZE32 #define SIZE32( x ) ((DWORD)( sizeof(x) / sizeof(DWORD) )) #endif /*****************************************************************************\ MACRO: SIZE64 \*****************************************************************************/ #ifndef SIZE64 #define SIZE64( x ) ((QWORD)( sizeof(x) / sizeof(QWORD) )) #endif /*****************************************************************************\ MACRO: OP_LENGTH \*****************************************************************************/ #ifndef OP_LENGTH #define OP_LENGTH( x ) ((DWORD)(x) - 2 ) #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_enum_g8.h000066400000000000000000000135171363533017100263350ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_enum.h" namespace G6HWC { /*****************************************************************************\ MACRO: BITFIELD_RANGE PURPOSE: Calculates the number of bits between the startbit and the endbit (0 based) \*****************************************************************************/ #ifndef BITFIELD_RANGE #define BITFIELD_RANGE(startbit,endbit) ((endbit)-(startbit)+1) #endif /*****************************************************************************\ MACRO: BITFIELD_BIT PURPOSE: Definition declared for clarity when creating structs \*****************************************************************************/ #ifndef BITFIELD_BIT #define BITFIELD_BIT(bit) 1 #endif /*****************************************************************************\ ENUM: INSTRUCTION_TYPE \*****************************************************************************/ enum INSTRUCTION_TYPE { INSTRUCTION_MI = 0x0, INSTRUCTION_TRUSTED = 0x1, INSTRUCTION_2D = 0x2, INSTRUCTION_GFX = 0x3 }; /*****************************************************************************\ ENUM: INSTRUCTION_SUBTYPE \*****************************************************************************/ enum INSTRUCTION_SUBTYPE { PIPE_COMMON = 0x0, PIPE_SINGLE_DWORD = 0x1, PIPE_MEDIA = 0x2, PIPE_3D = 0x3 }; /*****************************************************************************\ ENUM: GFX_OPCODE \*****************************************************************************/ enum GFX_OPCODE { GFXOP_MEDIA = 0x0, GFXOP_PIPELINED = 0x0, GFXOP_NONPIPELINED = 0x1, }; /*****************************************************************************\ ENUM: GFX_PIPELINED_SUBOPCODE \*****************************************************************************/ enum GFX_PIPELINED_SUBOPCODE { GFXSUBOP_STATE_POINTER_INVALIDATE = 0x2, GFXSUBOP_STATE_PREFETCH = 0x3 }; /*****************************************************************************\ ENUM: GFX_NONPIPELINED_SUBOPCODE \*****************************************************************************/ enum GFX_NONPIPELINED_SUBOPCODE { GFXSUBOP_STATE_BASE_ADDRESS = 0x1, GFXSUBOP_STATE_SIP = 0x2, GFXSUBOP_PIPELINE_SELECT = 0x4 }; /*****************************************************************************\ ENUM: GFXPIPELINE_SELECT \*****************************************************************************/ enum GFXPIPELINE_SELECT { GFXPIPELINE_3D = 0x0, GFXPIPELINE_MEDIA = 0x1, GFXPIPELINE_GPGPU = 0x2 }; /*****************************************************************************\ ENUM: GFXPIPELINE_SELECT_MASK \*****************************************************************************/ enum GFXPIPELINE_SELECT_MASK { GFXPIPELINE_SELECT_DISABLE = 0x0, GFXPIPELINE_SELECT_ENABLE = 0x3 }; /*****************************************************************************\ ENUM: GFXSTATE_GRAPHICS_DATATYPE_SOURCE \*****************************************************************************/ enum GFXSTATE_GRAPHICS_DATATYPE_SOURCE { GFXSTATE_GFDT_SOURCE_GTT = 0x0, GFXSTATE_GFDT_SOURCE_SURFACE = 0x1 }; /*****************************************************************************\ ENUM: GFXSTATE_CACHEABILITY_CONTROL \*****************************************************************************/ enum GFXSTATE_CACHEABILITY_CONTROL { GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY = 0x0, GFXSTATE_CACHEABILITY_CONTROL_NEITHER_LLC_NOR_MLC = 0x1, GFXSTATE_CACHEABILITY_CONTROL_LLC_NOT_MLC = 0x2, GFXSTATE_CACHEABILITY_CONTROL_LLC_AND_MLC = 0x3 }; /*****************************************************************************\ ENUM: GFXSTATE_SOURCE_AGE_CONTROL \*****************************************************************************/ enum GFXSTATE_SOURCE_AGE_CONTROL { GFXSTATE_SOURCE_AGE_CONTROL_POOR_HIT_CHANCE = 0x0, GFXSTATE_SOURCE_AGE_CONTROL_DECENT_HIT_CHANCE = 0x1, GFXSTATE_SOURCE_AGE_CONTROL_GOOD_HIT_CHANCE = 0x2, GFXSTATE_SOURCE_AGE_CONTROL_BEST_HIT_CHANCE = 0x3 }; /*****************************************************************************\ ENUM: GFXSTATE_TARGET_CACHE \*****************************************************************************/ enum GFXSTATE_TARGET_CACHE { GFXSTATE_TARGET_CACHE_ELLC_ONLY = 0x0, GFXSTATE_TARGET_CACHE_LLC_ONLY = 0x1, GFXSTATE_TARGET_CACHE_LLC_AND_ELLC = 0x2, GFXSTATE_TARGET_CACHE_L3_AND_LLC_AND_ELLC = 0x3 }; } // namespace G6HWCintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_init_g8.h000066400000000000000000000316611363533017100263340ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_enum_g6.h" #include "cmd_def_g6.h" namespace G6HWC { /*****************************************************************************\ CONST: g_cInitGfxPipelineSelect \*****************************************************************************/ const SGfxPipelineSelect g_cInitGfxPipelineSelect = { // DWORD 0 { GFXPIPELINE_3D, // PipelineSelect GFXSUBOP_PIPELINE_SELECT, // InstructionSubOpcode GFXOP_NONPIPELINED, // InstructionOpcode PIPE_SINGLE_DWORD, // InstructionSubType INSTRUCTION_GFX // InstructionType } }; /*****************************************************************************\ CONST: g_cInitGfxPipelineSelectGen9 \*****************************************************************************/ const SGfxPipelineSelect::_DW0::_Gen9 g_cInitGfxPipelineSelectGen9 = { GFXPIPELINE_GPGPU, // PipelineSelect GFXPIPELINE_SELECT_ENABLE, // PipelineSelectMask GFXSUBOP_PIPELINE_SELECT, // InstructionSubOpcode GFXOP_NONPIPELINED, // InstructionOpcode PIPE_SINGLE_DWORD, // InstructionSubType INSTRUCTION_GFX // InstructionType }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddress \*****************************************************************************/ const SGfxIndirectStateBaseAddress g_cInitGfxIndirectStateBaseAddress = { // DWORD 0 { OP_LENGTH( SIZE32( SGfxIndirectStateBaseAddress ) ),// Length GFXSUBOP_STATE_BASE_ADDRESS, // InstructionSubOpcode GFXOP_NONPIPELINED, // InstructionOpcode PIPE_COMMON, // InstructionSubType INSTRUCTION_GFX // InstructionType }, // DWORD 1 { true, // GeneralStateBaseAddressModify GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // GeneralStateCacheabilityControl GFXSTATE_GFDT_SOURCE_GTT, // GeneralStateGraphicsDataType false, // GeneralStateEncryptedDataEnable GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // StatelessDataPortCacheabilityControl GFXSTATE_GFDT_SOURCE_GTT, // StatelessDataPortGraphicsDataType false, // StatelessDataPortEncryptedDataEnable 0 // GeneralStateBaseAddress }, // DWORD 2 { true, // SurfaceStateBaseAddressModify GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // SurfaceStateCacheabilityControl GFXSTATE_GFDT_SOURCE_GTT, // SurfaceStateGraphicsDataType false, // SurfaceStateEncryptedDataEnable 0 // SurfaceStateBaseAddress }, // DWORD 3 { true, // DynamicStateBaseAddressModify GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // DynamicStateCacheabilityControl GFXSTATE_GFDT_SOURCE_GTT, // DynamicStateGraphicsDataType false, // DynamicStateEncryptedDataEnable 0 // DynamicStateBaseAddress }, // DWORD 4 { true, // IndirectObjectBaseAddressModify GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // IndirectObjectCacheabilityControl GFXSTATE_GFDT_SOURCE_GTT, // IndirectObjectGraphicsDataType false, // IndirectObjectEncryptedDataEnable 0 // IndirectObjectBaseAddress }, // DWORD 5 { true, // InstructionBaseAddressModify GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // InstructionMemoryCacheabilityControl GFXSTATE_GFDT_SOURCE_GTT, // InstructionMemoryGraphicsDataType false, // InstructionMemoryEncryptedDataEnable 0 // InstructionBaseAddress }, // DWORD 6 { true, // GeneralStateAccessUpperBoundModify 0 // GeneralStateAccessUpperBound }, // DWORD 7 { true, // DynamicStateAccessUpperBoundModify 0 // DynamicStateAccessUpperBound }, // DWORD 8 { true, // IndirectObjectStateAccessUpperBoundModify 0 // IndirectObjectStateAccessUpperBound }, // DWORD 9 { true, // InstructionAccessUpperBoundModify 0 // InstructionAccessUpperBound } }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddressDW4Gen8 \*****************************************************************************/ const SGfxIndirectStateBaseAddress::_DW4::_Gen8 g_cInitGfxIndirectStateBaseAddressDW4Gen8 = { true, // SurfaceStateBaseAddressModifyEnable GFXSTATE_SOURCE_AGE_CONTROL_POOR_HIT_CHANCE, // SurfaceStateAgeControl false, // SurfaceStateEncryptedDataEnable GFXSTATE_TARGET_CACHE_ELLC_ONLY, // SurfaceStateTargetCache GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // SurfaceStateCacheabilityControl 0 // SurfaceStateBaseAddress }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddressDW6Gen8 \*****************************************************************************/ const SGfxIndirectStateBaseAddress::_DW6::_Gen8 g_cInitGfxIndirectStateBaseAddressDW6Gen8 = { true, GFXSTATE_SOURCE_AGE_CONTROL_POOR_HIT_CHANCE, false, GFXSTATE_TARGET_CACHE_ELLC_ONLY, GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, 0 }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddressDW8Gen8 \*****************************************************************************/ const SGfxIndirectStateBaseAddress::_DW8::_Gen8 g_cInitGfxIndirectStateBaseAddressDW8Gen8 = { true, GFXSTATE_SOURCE_AGE_CONTROL_POOR_HIT_CHANCE, false, GFXSTATE_TARGET_CACHE_ELLC_ONLY, GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, 0 }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddressDW10Gen8 \*****************************************************************************/ const SGfxIndirectStateBaseAddress::_DW10::_Gen8 g_cInitGfxIndirectStateBaseAddressDW10Gen8 = { true, GFXSTATE_SOURCE_AGE_CONTROL_POOR_HIT_CHANCE, false, GFXSTATE_TARGET_CACHE_ELLC_ONLY, GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, 0 }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddressDW12Gen8 \*****************************************************************************/ const SGfxIndirectStateBaseAddress::_DW12::_Gen8 g_cInitGfxIndirectStateBaseAddressDW12Gen8 = { true, 0 }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddressDW13Gen8 \*****************************************************************************/ const SGfxIndirectStateBaseAddress::_DW13::_Gen8 g_cInitGfxIndirectStateBaseAddressDW13Gen8 = { true, 0 }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddressDW14Gen8 \*****************************************************************************/ const SGfxIndirectStateBaseAddress::_DW14::_Gen8 g_cInitGfxIndirectStateBaseAddressDW14Gen8 = { true, 0 }; /*****************************************************************************\ CONST: g_cInitGfxIndirectStateBaseAddressDW15Gen8 \*****************************************************************************/ const SGfxIndirectStateBaseAddress::_DW15::_Gen8 g_cInitGfxIndirectStateBaseAddressDW15Gen8 = { true, 0 }; /*****************************************************************************\ CONST: g_cInitGfxStatePointerInvalidate \*****************************************************************************/ const SGfxStatePointerInvalidate g_cInitGfxStatePointerInvalidate = { // DWORD 0 { false, // MediaStatePointerInvalidate false, // ConstantBufferInvalidate false, // PipelinedStatePointersInvalidate GFXSUBOP_STATE_POINTER_INVALIDATE, // InstructionSubOpcode GFXOP_PIPELINED, // InstructionOpcode PIPE_SINGLE_DWORD, // InstructionSubType INSTRUCTION_GFX // InstructionType } }; /*****************************************************************************\ CONST: g_cInitGfxStatePrefetch \*****************************************************************************/ const SGfxStatePrefetch g_cInitGfxStatePrefetch = { // DWORD 0 { OP_LENGTH( SIZE32( SGfxStatePrefetch ) ), // Length GFXSUBOP_STATE_PREFETCH, // InstructionSubOpcode GFXOP_PIPELINED, // InstructionOpcode PIPE_COMMON, // InstructionSubType INSTRUCTION_GFX // InstructionType }, // DWORD 1 { 0, // PrefetchCount 0 // PrefetchPointer } }; /*****************************************************************************\ CONST: g_cInitGfxSystemInstructionPointer \*****************************************************************************/ const SGfxSystemInstructionPointer g_cInitGfxSystemInstructionPointer = { // DWORD 0 { OP_LENGTH( SIZE32( SGfxSystemInstructionPointer ) ),// Length GFXSUBOP_STATE_SIP, // InstructionSubOpcode GFXOP_NONPIPELINED, // InstructionOpcode PIPE_COMMON, // InstructionSubType INSTRUCTION_GFX // InstructionType }, // DWORD 1 { 0 // SystemInstructionPointer } }; } // namespace G6HWCintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_media_caps_g8.cpp000066400000000000000000000216751363533017100300150ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include #include "cmd_media_caps_g8.h" #include "common/secure_mem.h" namespace G6HWC { /*****************************************************************************\ CONST: Caps \*****************************************************************************/ const DWORD g_cNumSamplersPerProgram = 16; const DWORD g_cNumSurfacesPerProgram = 252; const DWORD g_cNumSearchPathStatesGen6 = 14; const DWORD g_cNumMBModeSetsGen6 = 4; /*****************************************************************************\ CONST: g_cGen8HwCaps_GT4 \*****************************************************************************/ const SMediaHardwareCapabilities g_cGen8HwCaps_GT4 = { g_cNumSamplersPerProgram, // NumSamplersPerProgram g_cNumSurfacesPerProgram, // NumSurfacesPerProgram { // SamplerAnistropyRange 1, // Min 16, // Max }, 16384, // MaxSurface1DWidth 0, // MaxSurface1DHeight 2048, // MaxSurface1DDepth 16384, // MaxSurface2DWidth 16384, // MaxSurface2DHeight 2048, // MaxSurface2DDepth 2048, // MaxSurface3DWidth 2048, // MaxSurface3DHeight 2048, // MaxSurface3DDepth 16384, // MaxSurfaceCubeWidth 16384, // MaxSurfaceCubeHeight 0, // MaxSurfaceCubeDepth 14, // MaxSurfaceLODs 67108863, // MaxBufferLength { // SampleLOD 0.0f, // Min 14.0f // Max }, { // MipMapLODBias -16.0f, // Min 16.0f // Max }, { // URBEntryReadOffset 0, // Min 63 // Max }, { // URBEntryReadLength 1, // Min 63 // Max }, 31, // MaxURBPayloadStartRegister { // URBEntriesSize 4, // Min 256 // Max }, 32 * sizeof(DWORD), // URBEntrySize ( 128bytes = 1024bits ) 8 * sizeof(DWORD), // URBRowSize ( 32bytes = 256bits => 4 rows/entry ) 256 * sizeof(KILOBYTE), // URBSize ( 262144bytes * 1row/32bytes = 8192rows ) 0, // URBAllocationGranularitySize ( Used for L3 Allocation Gen7 ) 64 * sizeof(BYTE), // L2CacheLineSize 128 * sizeof(BYTE), // InstructionCachePrefetchSize 32 * sizeof(BYTE), // SurfaceStatePointerAlignSize 32 * sizeof(BYTE), // BindingTableStatePointerAlignSize 32 * sizeof(BYTE), // SamplerStatePointerAlignSize 64 * sizeof(BYTE), // KernelPointerAlignSize 1 * sizeof(KILOBYTE), // ScratchPointerAlignSize 64 * sizeof(BYTE), // DefaultColorPointerAlignSize 32 * sizeof(BYTE), // ConstantBufferPointerAlignSize 64 * sizeof(BYTE), // InterfaceDescriptorDataAlignSize 4 * sizeof(KILOBYTE), // GeneralStateBaseAddressAlignSize 4 * sizeof(KILOBYTE), // SurfaceStateBaseAddressAlignSize 4 * sizeof(KILOBYTE), // DynamicStateBaseAddressAlignSize 4 * sizeof(KILOBYTE), // IndirectObjectBaseAddressAlignSize 4 * sizeof(KILOBYTE), // InstructionBaseAddressAlignSize 16 * sizeof(BYTE), // SIPPointerAlignSize { // KernelHardwareCapabilities 8, // NumUserClipPlanes 7 * 128, // NumHardwareGRFRegisters 128, // NumSoftwareGRFRegisters //GT has fixed 128 GRFs per thread, and the allocation granularity //should also be 128 instead of 16. 128, // NumGRFRegistersPerBlock 0, // NumMRFRegisters; // MRF registers not used since gen7 2, // NumFlagRegisters 3, // URBRowsPerSetupWrite 71, // EUCount; { // EUCountPerSubSlice 7, // Min 8 // Max }, 9, // SubSliceCount 0, // EUIDCount; // Not used on gen8 7, // EUThreadsPerEU 0, // EUReservedGrfRegister 4, // EUReservedGrfSubRegister 0, // EUGrfMrfRegisterSizeInBytes; // Not used on gen8 0x01000000, // EUIStackUnderflowException 0x02000000, // EUIStackOverflowException 0x04000000, // EULStackUnderflowException 0x08000000, // EULStackOverflowException 0x10000000, // EUIllegalOpcodeException 0x20000000, // EUSoftwareExceptionControl 14, // EUMaxSoftwareStackValue 15, // EUMaxHardwareStackValue 0x00000000, // EUStackSoftwareOverflow; 0x01000000, // EUStackSoftwareUnderflow; 0x02000000, // EUStackSoftwareI; 0x04000000, // EUStackSoftwareL; 0x08000000, // EUStackSoftwareFunctionCall; 2, // EUJumpCountPerInstruction { // EUInstructionJumpLimit -32768, // Min 32767 // Max }, { // MediaScratchSpacePerThread sizeof(KILOBYTE), // Min 2 * sizeof(MEGABYTE) // Max }, 48 * sizeof(KILOBYTE), // InstructionCacheSize 16 * sizeof(KILOBYTE), // RenderCacheSize 64 * sizeof(BYTE), // KernelPointerAlignSize 252, // MaxAssignableBindingTableIndex; 255, // StatelessModelBindingTableIndex; true, // HasSharedLocalMemory 254, // SharedLocalMemoryBindingTableIndex true, // HasCoherentIAAccess 253, // CoherentIAAccessBindingTableIndex; { // RenderUnit true, // IsBarycentricInterpolationSupported true, // IsInstructionCompactionSupported }, { // DataPort 3, // OwordBlockTypes { 2, // OwordBlockCount[0] 4, // OwordBlockCount[1] 8 // OwordBlockCount[2] }, 2, // OwordDualBlockTypes { 1, // OwordDualBlockCount[0] 4 // OwordDualBlockCount[1] } }, false // HasDbgReg } }; void InitializeCapsGen8( SMediaHardwareCapabilities* pCaps ) { memcpy_s( pCaps, sizeof(SMediaHardwareCapabilities), &g_cGen8HwCaps_GT4, sizeof(SMediaHardwareCapabilities) ); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_media_caps_g8.h000066400000000000000000000152321363533017100274520ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "../sp/sp_types.h" namespace G6HWC { /*****************************************************************************\ STRUCT: SRange \*****************************************************************************/ #ifdef __cplusplus template struct SRange { Type Min; Type Max; }; template struct SRangeA { Type Min; Type Max; SRangeA( const Type min, const Type max ) { Min = min; Max = max; }; }; #endif /*****************************************************************************\ STRUCT: S3DRender \*****************************************************************************/ struct S3DRenderUnitCapabilities { DWORD IsBarycentricInterpolationSupported : 1; // BIT(0) DWORD IsInstructionCompactionSupported : 1; // BIT(1) DWORD :14; }; /*****************************************************************************\ STRUCT: S3DDataPort \*****************************************************************************/ struct S3DDataPortCapabilities { DWORD OwordBlockTypes; DWORD OwordBlockCount[3]; DWORD OwordDualBlockTypes; DWORD OwordDualBlockCount[2]; }; /*****************************************************************************\ STRUCT: S3DKernelHardwareCapabilities \*****************************************************************************/ struct S3DKernelHardwareCapabilities { DWORD NumUserClipPlanes; DWORD NumHardwareGRFRegisters; DWORD NumSoftwareGRFRegisters; DWORD NumGRFRegistersPerBlock; DWORD NumMRFRegisters; DWORD NumFlagRegisters; DWORD URBRowsPerSetupWrite; DWORD EUCount; SRange EUCountPerSubSlice; DWORD SubSliceCount; DWORD EUIDCount; DWORD EUThreadsPerEU; DWORD EUReservedGrfRegister; DWORD EUReservedGrfSubRegister; DWORD EUGrfMrfRegisterSizeInBytes; DWORD EUIStackUnderflowException; // not used DWORD EUIStackOverflowException; // not used DWORD EULStackUnderflowException; // not used DWORD EULStackOverflowException; // not used DWORD EUIllegalOpcodeException; // not used DWORD EUSoftwareExceptionControl; DWORD EUMaxSoftwareStackValue; DWORD EUMaxHardwareStackValue; // not used DWORD EUStackSoftwareOverflow; DWORD EUStackSoftwareUnderflow; DWORD EUStackSoftwareI; DWORD EUStackSoftwareL; DWORD EUStackSoftwareFunctionCall; DWORD EUJumpCountPerInstruction; SRange EUInstructionJumpLimit; SRange ScratchSpacePerThread; DWORD InstructionCacheSize; DWORD RenderCacheSize; DWORD KernelPointerAlignSize; DWORD MaxAssignableBindingTableIndex; DWORD StatelessModelBindingTableIndex; bool HasSharedLocalMemory; DWORD SharedLocalMemoryBindingTableIndex; bool HasCoherentIAAccess; DWORD CoherentIAAccessBindingTableIndex; S3DRenderUnitCapabilities RenderUnit; S3DDataPortCapabilities DataPort; bool HasDbgReg; }; /*****************************************************************************\ STRUCT: SMediaHardwareCapabilities \*****************************************************************************/ struct SMediaHardwareCapabilities { DWORD NumSamplersPerProgram; DWORD NumSurfacesPerProgram; SRange SamplerAnistropyRange; // TODO: these should be range per surface type DWORD MaxSurface1DWidth; DWORD MaxSurface1DHeight; DWORD MaxSurface1DDepth; DWORD MaxSurface2DWidth; DWORD MaxSurface2DHeight; DWORD MaxSurface2DDepth; DWORD MaxSurface3DWidth; DWORD MaxSurface3DHeight; DWORD MaxSurface3DDepth; DWORD MaxSurfaceCubeWidth; DWORD MaxSurfaceCubeHeight; DWORD MaxSurfaceCubeDepth; DWORD MaxSurfaceLODs; DWORD MaxBufferLength; SRange SampleLOD; SRange MipMapLODBias; SRange URBEntryReadOffset; SRange URBEntryReadLength; DWORD MaxURBPayloadStartRegister; SRange URBEntriesSize; DWORD URBEntrySize; DWORD URBRowSize; DWORD URBSize; DWORD URBAllocationGranularitySize; // Bytes DWORD L2CacheLineSize; DWORD InstructionCachePrefetchSize; DWORD SurfaceStatePointerAlignSize; DWORD BindingTableStatePointerAlignSize; DWORD SamplerStatePointerAlignSize; DWORD KernelPointerAlignSize; DWORD ScratchPointerAlignSize; DWORD DefaultColorPointerAlignSize; DWORD ConstantBufferPointerAlignSize; DWORD InterfaceDescriptorDataAlignSize; DWORD GeneralStateBaseAddressAlignSize; DWORD SurfaceStateBaseAddressAlignSize; DWORD DynamicStateBaseAddressAlignSize; DWORD IndirectObjectBaseAddressAlignSize; DWORD InstructionBaseAddressAlignSize; DWORD SIPPointerAlignSize; S3DKernelHardwareCapabilities KernelHwCaps; }; /*****************************************************************************\ PROTOTYPE: InitializeCapsGen8 \*****************************************************************************/ void InitializeCapsGen8( SMediaHardwareCapabilities* pCaps ); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_media_def_g8.h000066400000000000000000001001711363533017100272570ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_media_enum_g8.h" // Set packing alignment to a single byte #pragma pack(1) namespace G6HWC { /*****************************************************************************\ STRUCT: SMediaStateInterfaceDescriptorData (INTERFACE_DESCRIPTOR_DATA) \*****************************************************************************/ struct SMediaStateInterfaceDescriptorData { // DWORD 0 union _DW0 { struct _All { DWORD _Unused : BITFIELD_RANGE( 0, 5 ); DWORD KernelStartPointer : BITFIELD_RANGE( 6, 31 ); // GTT[31:6] } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD _Unused1 : BITFIELD_RANGE( 0, 6 ); DWORD SoftwareExceptionEnable : BITFIELD_BIT( 7 ); // bool DWORD _Unused2 : BITFIELD_RANGE( 8, 10 ); DWORD MaskStackExceptionEnable : BITFIELD_BIT( 11 ); // bool DWORD _Unused3 : BITFIELD_BIT( 12 ); DWORD IllegalOpcodeExceptionEnable : BITFIELD_BIT( 13 ); // bool DWORD _Unused4 : BITFIELD_RANGE( 14, 15 ); DWORD FloatingPointMode : BITFIELD_BIT( 16 ); // GFXMEDIASTATE_FLOATING_POINT_MODE DWORD ThreadPriority : BITFIELD_BIT( 17 ); // GFXMEDIASTATE_THREAD_PRIORITY DWORD SingleProgramFlow : BITFIELD_BIT( 18 ); // GFXMEDIASTATE_SINGLE_PROGRAM_FLOW DWORD _Unused5 : BITFIELD_BIT( 19 ); DWORD _Unused6 : BITFIELD_RANGE( 20, 25 ); // U6 [0,63] DWORD _Unused7 : BITFIELD_RANGE( 26, 31 ); // U6 [0,63] } All; struct _Gen8 { DWORD Kernel64bitStartPointer : BITFIELD_RANGE( 0, 15 ); // GTT[47:32] DWORD _Unused : BITFIELD_RANGE( 16, 31 ); // Reserved } Gen8; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD _Unused : BITFIELD_RANGE( 0, 1 ); DWORD SamplerCount : BITFIELD_RANGE( 2, 4 ); // U3 [0,4] DWORD SamplerStatePointer : BITFIELD_RANGE( 5, 31 ); // GTT[31:5] } All; struct _Gen8 { DWORD _Unused1 : BITFIELD_RANGE( 0, 6 ); DWORD SoftwareExceptionEnable : BITFIELD_BIT( 7 ); // bool DWORD _Unused2 : BITFIELD_RANGE( 8, 10 ); DWORD MaskStackExceptionEnable : BITFIELD_BIT( 11 ); // bool DWORD _Unused3 : BITFIELD_BIT( 12 ); DWORD IllegalOpcodeExceptionEnable : BITFIELD_BIT( 13 ); // bool DWORD _Unused4 : BITFIELD_RANGE( 14, 15 ); DWORD FloatingPointMode : BITFIELD_BIT( 16 ); // GFXMEDIASTATE_FLOATING_POINT_MODE DWORD ThreadPriority : BITFIELD_BIT( 17 ); // GFXMEDIASTATE_THREAD_PRIORITY DWORD SingleProgramFlow : BITFIELD_BIT( 18 ); // GFXMEDIASTATE_SINGLE_PROGRAM_FLOW DWORD DenormMode : BITFIELD_BIT( 19 ); // U1 [0,1] DWORD _Unused5 : BITFIELD_RANGE( 20, 31 ); // Reserved } Gen8; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD BindingTableEntryCount : BITFIELD_RANGE( 0, 4 ); // U5 [0,5] DWORD BindingTablePointer : BITFIELD_RANGE( 5, 31 ); // GTT[31:5] } All; struct _Gen8 { DWORD _Unused : BITFIELD_RANGE( 0, 1 ); // Reserved DWORD SamplerCount : BITFIELD_RANGE( 2, 4 ); // U3 [0,4] DWORD SamplerStatePointer : BITFIELD_RANGE( 5, 31 ); // GTT[31:5] } Gen8; DWORD Value; } DW3; // DWORD 4 union _DW4 { struct _All { DWORD ConstantURBEntryReadOffset : BITFIELD_RANGE( 0, 15 ); DWORD ConstantURBEntryReadLength : BITFIELD_RANGE( 16, 31 ); } All; struct _Gen8 { DWORD BindingTableEntryCount : BITFIELD_RANGE( 0, 4 ); // U5 [0,31] DWORD BindingTablePointer : BITFIELD_RANGE( 5, 15 ); // GTT[15:5] DWORD _Unused : BITFIELD_RANGE( 16, 31 ); // Reserved } Gen8; DWORD Value; } DW4; // DWORD 5 union _DW5 { struct _All { DWORD BarrierId : BITFIELD_RANGE( 0, 3 ); DWORD _Unused : BITFIELD_RANGE( 4, 31); } All; struct _Gen7 { DWORD NumberOfThreadsInThreadGroup : BITFIELD_RANGE( 0, 7 ); // U8 DWORD _Unused1 : BITFIELD_RANGE( 8, 15 ); DWORD SharedLocalMemorySize : BITFIELD_RANGE( 16, 20 ); // U5 DWORD BarrierEnable : BITFIELD_BIT( 21 ); // bool DWORD RoundingMode : BITFIELD_RANGE( 22, 23 ); // U2 DWORD _Unused2 : BITFIELD_RANGE( 24, 31 ); } Gen7; struct _Gen8 { DWORD ConstantURBEntryReadOffset : BITFIELD_RANGE( 0, 15 ); DWORD ConstantURBEntryReadLength : BITFIELD_RANGE( 16, 31 ); } Gen8; DWORD Value; } DW5; // DWORD 6 union _DW6 { struct _Gen7_5 { DWORD CrossThreadConstantDataReadLength : BITFIELD_RANGE( 0, 7 ); // U8 DWORD _Unused : BITFIELD_RANGE( 8, 31 ); } Gen7_5; struct _Gen8 { DWORD NumberOfThreadsInThreadGroup : BITFIELD_RANGE( 0, 9 ); // U9 DWORD _Unused1 : BITFIELD_RANGE( 10, 14 ); // Reserved DWORD GlobalBarrierEnable : BITFIELD_BIT( 15 ); // bool DWORD SharedLocalMemorySize : BITFIELD_RANGE( 16, 20 ); // U5 DWORD BarrierEnable : BITFIELD_BIT( 21 ); // bool DWORD RoundingMode : BITFIELD_RANGE( 22, 23 ); // U2 DWORD _Unused2 : BITFIELD_RANGE( 24, 31 ); // Reserved } Gen8; DWORD Value; } DW6; // DWORD 7 union _DW7 { struct _Gen8 { DWORD CrossThreadConstantDataReadLength : BITFIELD_RANGE( 0, 7 ); // U8 DWORD _Unused : BITFIELD_RANGE( 8, 31 ); // Reserved } Gen8; DWORD Value; } DW7; }; static_assert(SIZE32(SMediaStateInterfaceDescriptorData) == 8); /*****************************************************************************\ STRUCT: SMediaStateMediaInterfaceDescriptorLoad (MEDIA_INTERFACE_DESCRIPTOR_LOAD) \*****************************************************************************/ struct SMediaStateMediaInterfaceDescriptorLoad { union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE( 0, 15 ); // OP_LENGTH (exclude dw0,dw1) DWORD InstructionSubOpcode : BITFIELD_RANGE( 16, 23 ); // GFX_MEDIA_PIPELINED_SUBOPCODE DWORD InstructionOpcode : BITFIELD_RANGE( 24, 26 ); // GFX_OPCODE DWORD InstructionSubType : BITFIELD_RANGE( 27, 28 ); // INSTRUCTION_SUBTYPE DWORD InstructionType : BITFIELD_RANGE( 29, 31 ); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD InterfaceDescriptorTotalLength : BITFIELD_RANGE( 0, 16 ); DWORD _Unused : BITFIELD_RANGE( 17, 31 ); } All; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD InterfaceDescriptorDataStartAddress : BITFIELD_RANGE( 0, 31 ); } All; DWORD Value; } DW3; }; static_assert(SIZE32(SMediaStateMediaInterfaceDescriptorLoad) == 4); /*****************************************************************************\ STRUCT: SMediaStateMediaVFEState (MEDIA_VFE_STATE) \*****************************************************************************/ struct SMediaStateMediaVFEState { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE( 0, 15 ); // OP_LENGTH (exclude dw0,dw1) DWORD InstructionSubOpcode : BITFIELD_RANGE( 16, 23 ); // GFX_MEDIA_PIPELINED_SUBOPCODE DWORD InstructionOpcode : BITFIELD_RANGE( 24, 26 ); // GFX_OPCODE DWORD InstructionSubType : BITFIELD_RANGE( 27, 28 ); // INSTRUCTION_SUBTYPE DWORD InstructionType : BITFIELD_RANGE( 29, 31 ); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD PerThreadScratchSpace : BITFIELD_RANGE( 0, 3 ); // U4 [0, 11] -> [1k, 12k] DWORD StackSize : BITFIELD_RANGE( 4, 7 ); // U4 [0, 11] -> [1k, 2MB] DWORD _Unused : BITFIELD_RANGE( 8, 9 ); // reserved DWORD ScratchSpaceBasePointer : BITFIELD_RANGE( 10, 31 ); // GTT[31:10] } All; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD DebugCounterControl : BITFIELD_RANGE( 0, 1 ); // GFXMEDIASTATE_DEBUG_COUNTER_CONTROL DWORD _Unused : BITFIELD_RANGE( 2, 4 ); DWORD FastPreempt : BITFIELD_BIT( 5 ); // bool DWORD BypassGatewayControl : BITFIELD_BIT( 6 ); // bool DWORD ResetGatewayTimer : BITFIELD_BIT( 7 ); // bool DWORD NumberOfURBEntries : BITFIELD_RANGE( 8, 15 ); // U8 [0,64] DWORD MaximumNumberOfThreads : BITFIELD_RANGE( 16, 31 ); // U16 = thread count -1 } All; struct _Gen7 { DWORD DebugCounterControl : BITFIELD_RANGE( 0, 1 ); // GFXMEDIA_DEBUG_COUNTER_CONTROL DWORD GPGPUMode : BITFIELD_BIT( 2 ); // GFXMEDIA_GPGPU_MODE DWORD GatewayMMIOAccessControl : BITFIELD_RANGE( 3, 4 ); // GFXMEDIA_MMIO_ACCESS_CONTROL DWORD FastPreemptEnable : BITFIELD_BIT( 5 ); // bool DWORD BypassGatewayControl : BITFIELD_BIT( 6 ); DWORD ResetGatewayTimer : BITFIELD_BIT( 7 ); DWORD NumberofURBEntries : BITFIELD_RANGE( 8, 15 ); // U8 DWORD MaximumNumberOfThreads : BITFIELD_RANGE( 16, 31 ); // U4 } Gen7; struct _Gen8 { DWORD ScratchSpace64bitBasePointer : BITFIELD_RANGE( 0, 15 ); // GTT[47:32] DWORD _Unused : BITFIELD_RANGE( 16, 31 ); // reserved } Gen8; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD _Unused : BITFIELD_RANGE( 0, 7 ); DWORD ObjectId : BITFIELD_RANGE( 8, 31 ); } All; struct _Gen8 { DWORD DebugCounterControl : BITFIELD_RANGE( 0, 1 ); // GFXMEDIA_DEBUG_COUNTER_CONTROL DWORD GPGPUMode : BITFIELD_BIT( 2 ); // GPGPUMode DWORD GatewayMMIOAccessControl : BITFIELD_RANGE( 3, 4 ); // GFXMEDIA_MMIO_ACCESS_CONTROL DWORD FastPreemptEnable : BITFIELD_BIT( 5 ); // bool DWORD BypassGatewayControl : BITFIELD_BIT( 6 ); DWORD ResetGatewayTimer : BITFIELD_BIT( 7 ); DWORD NumberofURBEntries : BITFIELD_RANGE( 8, 15 ); // U8 DWORD MaximumNumberOfThreads : BITFIELD_RANGE( 16, 31 ); // U4 } Gen8; struct _Gen9 { DWORD DebugCounterControl : BITFIELD_RANGE( 0, 1 ); // GFXMEDIA_DEBUG_COUNTER_CONTROL DWORD SLMGranularity : BITFIELD_BIT( 2 ); // GFXMEDIASTATE_SLMGranularity DWORD GatewayMMIOAccessControl : BITFIELD_RANGE( 3, 4 ); // GFXMEDIA_MMIO_ACCESS_CONTROL DWORD _Unused : BITFIELD_BIT( 5 ); // reserved DWORD BypassGatewayControl : BITFIELD_BIT( 6 ); DWORD ResetGatewayTimer : BITFIELD_BIT( 7 ); DWORD NumberofURBEntries : BITFIELD_RANGE( 8, 15 ); // U8 DWORD MaximumNumberOfThreads : BITFIELD_RANGE( 16, 31 ); // U4 } Gen9; DWORD Value; } DW3; // DWORD 4 union _DW4 { struct _All { DWORD CURBEAllocationSize : BITFIELD_RANGE( 0, 15 ); // U9 [0, 2048] DWORD URBEntryAllocationSize : BITFIELD_RANGE( 16, 31 ); // U9 [0, 2048] } All; struct _Gen8 { DWORD _Unused : BITFIELD_RANGE( 0, 7 ); // reserved DWORD ObjectID : BITFIELD_RANGE( 8, 31 ); } Gen8; struct _Gen10 { DWORD SliceDisable : BITFIELD_RANGE( 0, 1 ); DWORD FlushOnBarriers : BITFIELD_RANGE( 2, 3 ); DWORD _Unused : BITFIELD_RANGE( 4, 7 ); // reserved DWORD ObjectID : BITFIELD_RANGE( 8, 31 ); } Gen10; DWORD Value; } DW4; // DWORD 5 union _DW5 { struct _All { DWORD ScoreboardMask : BITFIELD_RANGE( 0, 7 ); // 8 bits for score 0 to 7 DWORD _Unused : BITFIELD_RANGE( 8, 29 ); DWORD ScoreBoardType : BITFIELD_BIT( 30 ); // GFXMEDIASTATE_SCOREBOARD_TYPE DWORD ScoreBoardEnable : BITFIELD_BIT( 31 ); // bool } All; struct _Gen8 { DWORD CURBEAllocationSize : BITFIELD_RANGE( 0, 15 ); // U9 [0, 2048] DWORD URBEntryAllocationSize : BITFIELD_RANGE( 16, 31 ); // U9 [0, 2048] } Gen8; DWORD Value; } DW5; // DWORD 6 union _DW6 { struct _All { DWORD ScoreboardDeltaX0 : BITFIELD_RANGE( 0, 3 ); // s3 DWORD ScoreboardDeltaY0 : BITFIELD_RANGE( 4, 7 ); // s3 DWORD ScoreboardDeltaX1 : BITFIELD_RANGE( 8, 11 ); // s3 DWORD ScoreboardDeltaY1 : BITFIELD_RANGE( 12, 15 ); // s3 DWORD ScoreboardDeltaX2 : BITFIELD_RANGE( 16, 19 ); // s3 DWORD ScoreboardDeltaY2 : BITFIELD_RANGE( 20, 23 ); // s3 DWORD ScoreboardDeltaX3 : BITFIELD_RANGE( 24, 27 ); // s3 DWORD ScoreboardDeltaY3 : BITFIELD_RANGE( 28, 31 ); // s3 } All; struct _Gen8 { DWORD ScoreboardMask : BITFIELD_RANGE( 0, 7 ); // 8 bits for score 0 to 7 DWORD _Unused : BITFIELD_RANGE( 8, 29 ); DWORD ScoreBoardType : BITFIELD_BIT( 30 ); // GFXMEDIASTATE_SCOREBOARD_TYPE DWORD ScoreBoardEnable : BITFIELD_BIT( 31 ); // bool } Gen8; struct _Gen10 { DWORD ScoreboardMask : BITFIELD_RANGE( 0, 7 ); // 8 bits for score 0 to 7 DWORD NumMediaObjPerPreEmptionCheckpoint : BITFIELD_RANGE( 8, 15 ); // how many MEDIA_OBJECT commands are executed between checkpoints for pre-emption. DWORD _Unused : BITFIELD_RANGE( 16, 29 ); DWORD ScoreBoardType : BITFIELD_BIT( 30 ); // GFXMEDIASTATE_SCOREBOARD_TYPE DWORD ScoreBoardEnable : BITFIELD_BIT( 31 ); // bool } Gen10; DWORD Value; } DW6; // DWORD 7 union _DW7 { struct _All { DWORD ScoreboardDeltaX4 : BITFIELD_RANGE( 0, 3 ); // s3 DWORD ScoreboardDeltaY4 : BITFIELD_RANGE( 4, 7 ); // s3 DWORD ScoreboardDeltaX5 : BITFIELD_RANGE( 8, 11 ); // s3 DWORD ScoreboardDeltaY5 : BITFIELD_RANGE( 12, 15 ); // s3 DWORD ScoreboardDeltaX6 : BITFIELD_RANGE( 16, 19 ); // s3 DWORD ScoreboardDeltaY6 : BITFIELD_RANGE( 20, 23 ); // s3 DWORD ScoreboardDeltaX7 : BITFIELD_RANGE( 24, 27 ); // s3 DWORD ScoreboardDeltaY7 : BITFIELD_RANGE( 28, 31 ); // s3 } All; struct _Gen8 { DWORD ScoreboardDeltaX0 : BITFIELD_RANGE( 0, 3 ); // s3 DWORD ScoreboardDeltaY0 : BITFIELD_RANGE( 4, 7 ); // s3 DWORD ScoreboardDeltaX1 : BITFIELD_RANGE( 8, 11 ); // s3 DWORD ScoreboardDeltaY1 : BITFIELD_RANGE( 12, 15 ); // s3 DWORD ScoreboardDeltaX2 : BITFIELD_RANGE( 16, 19 ); // s3 DWORD ScoreboardDeltaY2 : BITFIELD_RANGE( 20, 23 ); // s3 DWORD ScoreboardDeltaX3 : BITFIELD_RANGE( 24, 27 ); // s3 DWORD ScoreboardDeltaY3 : BITFIELD_RANGE( 28, 31 ); // s3 } Gen8; DWORD Value; } DW7; // DWORD 8 union _DW8 { struct _Gen8 { DWORD ScoreboardDeltaX4 : BITFIELD_RANGE( 0, 3 ); // s3 DWORD ScoreboardDeltaY4 : BITFIELD_RANGE( 4, 7 ); // s3 DWORD ScoreboardDeltaX5 : BITFIELD_RANGE( 8, 11 ); // s3 DWORD ScoreboardDeltaY5 : BITFIELD_RANGE( 12, 15 ); // s3 DWORD ScoreboardDeltaX6 : BITFIELD_RANGE( 16, 19 ); // s3 DWORD ScoreboardDeltaY6 : BITFIELD_RANGE( 20, 23 ); // s3 DWORD ScoreboardDeltaX7 : BITFIELD_RANGE( 24, 27 ); // s3 DWORD ScoreboardDeltaY7 : BITFIELD_RANGE( 28, 31 ); // s3 } Gen8; DWORD Value; } DW8; }; static_assert(SIZE32(SMediaStateMediaVFEState) == 9); /*****************************************************************************\ STRUCT: SMediaStateMediaCURBELoad (MEDIA_CURBE_LOAD) \*****************************************************************************/ struct SMediaStateMediaCURBELoad { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE( 0, 15 ); // OP_LENGTH (exclude dw0,dw1) DWORD InstructionSubOpcode : BITFIELD_RANGE( 16, 23 ); // GFX_MEDIA_PIPELINED_SUBOPCODE DWORD InstructionOpcode : BITFIELD_RANGE( 24, 26 ); // GFX_OPCODE DWORD InstructionSubType : BITFIELD_RANGE( 27, 28 ); // INSTRUCTION_SUBTYPE DWORD InstructionType : BITFIELD_RANGE( 29, 31 ); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD CURBETotalDataLength : BITFIELD_RANGE( 0, 16 ); // U17 DWORD _Unused : BITFIELD_RANGE( 17, 31 ); } All; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD CURBEDataStartAddress : BITFIELD_RANGE( 0, 31 ); // U17 } All; DWORD Value; } DW3; }; static_assert(SIZE32(SMediaStateMediaCURBELoad) == 4); /*****************************************************************************\ STRUCT: SMediaStateMediaStateFlush (MEDIA_STATE_FLUSH) \*****************************************************************************/ struct SMediaStateMediaStateFlush { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE( 0, 15); // OP_LENGTH (exclude dw0,dw1) DWORD InstructionSubOpcode : BITFIELD_RANGE( 16, 23); // GFX_MEDIA_PIPELINED_SUBOPCODE DWORD InstructionOpcode : BITFIELD_RANGE( 24, 26); // GFX_OPCODE DWORD InstructionSubType : BITFIELD_RANGE( 27, 28); // INSTRUCTION_SUBTYPE DWORD InstructionType : BITFIELD_RANGE( 29, 31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD BarrierMask : BITFIELD_RANGE( 0, 15 ); // One bit for each barrier DWORD ThreadCountWaterMark : BITFIELD_RANGE( 16, 23 ); // U8 DWORD _Unused : BITFIELD_RANGE( 24, 31 ); } All; struct _Gen7 { DWORD InterfaceDescriptorOffset : BITFIELD_RANGE( 0, 5 ); // U6 DWORD ThreadCountWaterMark : BITFIELD_BIT( 6 ); // one bit specify if stall waiting resources DWORD _Unused : BITFIELD_RANGE( 7, 31 ); } Gen7; DWORD Value; } DW1; }; static_assert(SIZE32(SMediaStateMediaStateFlush) == 2); /*****************************************************************************\ STRUCT: SMediaStateGPGPUWalker (GPGPU_WALKER) \*****************************************************************************/ struct SMediaStateGPGPUWalker { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE( 0, 7 ); // OP_LENGTH (exclude dw0,dw1) DWORD PredicateEnable : BITFIELD_BIT( 8 ); // bool DWORD _Unused1 : BITFIELD_BIT( 9 ); DWORD IndirectParameterEnable : BITFIELD_BIT( 10 ); // bool DWORD _Unused2 : BITFIELD_RANGE( 11, 15 ); DWORD InstructionSubOpcodeA : BITFIELD_RANGE( 16, 23 ); // GFX_MEDIA_NONPIPELINED_SUBOPCODE_A DWORD InstructionOpcode : BITFIELD_RANGE( 24, 26 ); // GFX_OPCODE DWORD InstructionSubType : BITFIELD_RANGE( 27, 28 ); // INSTRUCTION_SUBTYPE DWORD InstructionType : BITFIELD_RANGE( 29, 31 ); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD InterfaceDescriptorOffset : BITFIELD_RANGE( 0, 5 ); // U5 DWORD _Unused : BITFIELD_RANGE( 6, 7 ); DWORD ObjectId : BITFIELD_RANGE( 8, 31 ); // U8 } All; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD ThreadWidthCounterMaximum : BITFIELD_RANGE( 0, 5 ); DWORD _Unused1 : BITFIELD_RANGE( 6, 7 ); DWORD ThreadHeightCounterMaximum : BITFIELD_RANGE( 8, 13 ); DWORD _Unused2 : BITFIELD_RANGE( 14, 15 ); DWORD ThreadDepthCounterMaximum : BITFIELD_RANGE( 16, 21 ); DWORD _Unused3 : BITFIELD_RANGE( 22, 29 ); DWORD SIMDSize : BITFIELD_RANGE( 30, 31 ); // GFXMEDIASTATE_GPGPU_WALKER_SIMD_SIZE } All; struct _Gen8 { DWORD IndirectDataLength : BITFIELD_RANGE( 0, 16 ); // U17 in bytes DWORD _Unused : BITFIELD_RANGE( 17, 31 ); // Reserved } Gen8; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD ThreadGroupIdStartingX : BITFIELD_RANGE( 0, 31 ); // U31 } All; struct _Gen8 { DWORD IndirectDataStartAddress : BITFIELD_RANGE( 0, 31 ); // 64-byte aligned address } Gen8; DWORD Value; } DW3; // DWORD 4 union _DW4 { struct _All { DWORD ThreadGroupIdDimensionX : BITFIELD_RANGE( 0, 31 ); } All; struct _Gen8 { DWORD ThreadWidthCounterMaximum : BITFIELD_RANGE( 0, 5 ); DWORD _Unused1 : BITFIELD_RANGE( 6, 7 ); // Reserved DWORD ThreadHeightCounterMaximum : BITFIELD_RANGE( 8, 13 ); DWORD _Unused2 : BITFIELD_RANGE( 14, 15 ); // Reserved DWORD ThreadDepthCounterMaximum : BITFIELD_RANGE( 16, 21 ); DWORD _Unused3 : BITFIELD_RANGE( 22, 29 ); // Reserved DWORD SIMDSize : BITFIELD_RANGE( 30, 31 ); // GFXMEDIASTATE_GPGPU_WALKER_SIMD_SIZE } Gen8; DWORD Value; } DW4; // DWORD 5 union _DW5 { struct _All { DWORD ThreadGroupIdStartingY : BITFIELD_RANGE( 0, 31 ); } All; struct _Gen8 { DWORD ThreadGroupIdStartingX : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW5; // DWORD 6 union _DW6 { struct _All { DWORD ThreadGroupIdDimensionY : BITFIELD_RANGE( 0, 31 ); } All; struct _Gen8 { DWORD ThreadGroupIdResumeX : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW6; // DWORD 7 union _DW7 { struct _All { DWORD ThreadGroupIdStartingZ : BITFIELD_RANGE( 0, 31 ); } All; struct _Gen8 { DWORD ThreadGroupIdDimensionX : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW7; // DWORD 8 union _DW8 { struct _All { DWORD ThreadGroupIdDimensionZ : BITFIELD_RANGE( 0, 31 ); } All; struct _Gen8 { DWORD ThreadGroupIdStartingY : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW8; // DWORD 9 union _DW9 { struct _All { DWORD RightExecutionMask : BITFIELD_RANGE( 0, 31 ); } All; struct _Gen8 { DWORD ThreadGroupIdResumeY : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW9; // DWORD 10 union _DW10 { struct _All { DWORD BottomExecutionMask : BITFIELD_RANGE( 0, 31 ); } All; struct _Gen8 { DWORD ThreadGroupIdDimensionY : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW10; // DWORD 11 union _DW11 { struct _Gen8 { DWORD ThreadGroupIdStartingResumeZ : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW11; // DWORD 12 union _DW12 { struct _Gen8 { DWORD ThreadGroupIdDimensionZ : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW12; // DWORD 13 union _DW13 { struct _Gen8 { DWORD RightExecutionMask : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW13; // DWORD 14 union _DW14 { struct _Gen8 { DWORD BottomExecutionMask : BITFIELD_RANGE( 0, 31 ); } Gen8; DWORD Value; } DW14; }; static_assert(SIZE32(SMediaStateGPGPUWalker) == 15); } // namespace G6HWC // Reset packing alignment to project default #pragma pack() intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_media_enum_g8.h000066400000000000000000000153071363533017100274730ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_enum_g8.h" namespace G6HWC { /*****************************************************************************\ ENUM: GFX_MEDIA_PIPELINED_SUBOPCODE \*****************************************************************************/ enum GFX_MEDIA_PIPELINED_SUBOPCODE { GFXSUBOP_MEDIA_VFE_STATE = 0x0, GFXSUBOP_MEDIA_CURBE_LOAD = 0x1, GFXSUBOP_MEDIA_INTERFACE_DESCRIPTOR_LOAD = 0x2, GFXSUBOP_MEDIA_GATEWAY_STATE = 0x3, GFXSUBOP_MEDIA_STATE_FLUSH = 0x4 }; /*****************************************************************************\ ENUM: GFX_MEDIA_NONPIPELINED_SUBOPCODE \*****************************************************************************/ enum GFX_MEDIA_NONPIPELINED_SUBOPCODE { GFXSUBOP_MEDIA_OBJECT = 0x0, GFXSUBOP_MEDIA_OBJECT_PRT = 0x2, GFXSUBOP_MEDIA_OBJECT_WALKER = 0x3 }; /*****************************************************************************\ ENUM: GFX_MEDIA_NONPIPELINED_SUBOPCODE_A \*****************************************************************************/ enum GFX_MEDIA_NONPIPELINED_SUBOPCODE_A { GFXSUBOP_MEDIA_GPGPU_WALKER = 0x5 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_DEBUG_COUNTER_CONTROL \*****************************************************************************/ enum GFXMEDIASTATE_DEBUG_COUNTER_CONTROL { GFXMEDIASTATE_DEBUG_COUNTER_FREE_RUNNING = 0x0, GFXMEDIASTATE_DEBUG_COUNTER_FROZEN = 0x1, GFXMEDIASTATE_DEBUG_COUNTER_INITIALIZED_ONCE = 0x2, GFXMEDIASTATE_DEBUG_COUNTER_INITIALIZED_ALWAYS = 0x3 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_FLOATING_POINT_MODE \*****************************************************************************/ enum GFXMEDIASTATE_FLOATING_POINT_MODE { GFXMEDIASTATE_FLOATING_POINT_IEEE_754 = 0x0, GFXMEDIASTATE_FLOATING_POINT_NON_IEEE_754 = 0x1 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_THREAD_PRIORITY \*****************************************************************************/ enum GFXMEDIASTATE_THREAD_PRIORITY { GFXMEDIASTATE_THREAD_PRIORITY_NORMAL = 0x0, GFXMEDIASTATE_THREAD_PRIORITY_HIGH = 0x1 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_VFE_MODE \*****************************************************************************/ enum GFXMEDIASTATE_VFE_MODE { GFXMEDIASTATE_VFE_MODE_GENERIC = 0x0, GFXMEDIASTATE_VFE_MODE_VLD = 0x1, GFXMEDIASTATE_VFE_MODE_IS = 0x2, GFXMEDIASTATE_VFE_MODE_AVC_MC = 0x4, GFXMEDIASTATE_VFE_MODE_AVC_IT = 0x7, GFXMEDIASTATE_VFE_MODE_VC1_IT = 0xB }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_GPGPU_MODE \*****************************************************************************/ enum GFXMEDIASTATE_GPGPU_MODE { GFXMEDIASTATE_GPGPU_MODE_MEDIA = 0x0, GFXMEDIASTATE_GPGPU_MODE_GPGPU = 0x1 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_SLM_GRANULARITY \*****************************************************************************/ enum GFXMEDIASTATE_SLM_GRANULARITY { GFXMEDIASTATE_SLM_GRANULARITY_4K = 0x0, GFXMEDIASTATE_SLM_GRANULARITY_1K = 0x1 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_MMIO_ACCESS_CONTROL \*****************************************************************************/ enum GFXMEDIASTATE_MMIO_ACCESS_CONTROL { GFXMEDIASTATE_MMIO_ACCESS_CONTROL_NO_READWRITE = 0x0, GFXMEDIASTATE_MMIO_ACCESS_CONTROL_OA_READWRITE = 0x1, GFXMEDIASTATE_MMIO_ACCESS_CONTROL_ANY_READWRITE = 0x2 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_SCOREBOARD_TYPE \*****************************************************************************/ enum GFXMEDIASTATE_SCOREBOARD_TYPE { GFXMEDIASTATE_STALLING_SCOREBOARD = 0x0, GFXMEDIASTATE_NONSTALLING_SCOREBOARD = 0x1 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_THREAD_SYNCHRONIZATION \*****************************************************************************/ enum GFXMEDIASTATE_THREAD_SYNCHRONIZATION { GFXMEDIASTATE_NO_THREAD_SYNCHRONIZATION = 0x0, GFXMEDIASTATE_THREAD_DISPATCH_SYNCHRONIZED = 0x1 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_PRT_FENCE_TYPE \*****************************************************************************/ enum GFXMEDIASTATE_PRT_FENCE_TYPE { GFXMEDIASTATE_ROOT_THREAD_QUEUE = 0x0, GFXMEDIASTATE_VFE_STATE_FLUSH = 0x1 }; /*****************************************************************************\ ENUM: GFXMEDIASTATE_GPGPU_WALKER_SIMD_SIZE \*****************************************************************************/ enum GFXMEDIASTATE_GPGPU_WALKER_SIMD_SIZE { GFXMEDIASTATE_GPGPU_WALKER_SIMD8 = 0x0, GFXMEDIASTATE_GPGPU_WALKER_SIMD16 = 0x1, GFXMEDIASTATE_GPGPU_WALKER_SIMD32 = 0x2 }; } // namespace G6HWCintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_media_init_g8.h000066400000000000000000000535731363533017100275010ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_media_enum_g8.h" #include "cmd_media_def_g8.h" #include "cmd_3d_enum_g8.h" namespace G6HWC { /*****************************************************************************\ CONST: g_cInitMediaStateInterfaceDescriptorData \*****************************************************************************/ static const SMediaStateInterfaceDescriptorData g_cInitMediaStateInterfaceDescriptorData = { // DW0 { { 0, // _Unused 0 // KernelStartPointer } }, // DW1 { { 0, // _Unused1 false, // SoftwareExceptionEnable 0, // _Unused2 false, // MaskStackExceptionEnable 0, // _Unused3 false, // IllegalOpcodeExceptionEnable 0, // _Unused4 GFXMEDIASTATE_FLOATING_POINT_IEEE_754, // FloatingPointMode GFXMEDIASTATE_THREAD_PRIORITY_NORMAL, // ThreadPriority true, // SingleProgramFlow 0, // _Unused5 0, // _Unused6 0 // _Unused7 } }, // DW2 { { 0, // _Unused 0, // SamplerCount 0 // SamplerStatePointer } }, // DW3 { { 0, // BindingTableEntryCount 0 // BindingTablePointer } }, // DW4 { { 0, // ConstantURBEntryReadOffset 0 // ConstantURBEntryReadLength } }, // DW5 { { 0, // BarrierId 0 // _Unused } }, // DW6 { { 0, // CrossThreadConstantDataReadLength 0 // _Unused } }, // DW7 { { 0, // CrossThreadConstantDataReadLength 0 // _Unused } } }; /*****************************************************************************\ CONST: g_cInitMediaStateInterfaceDescriptorDataDW5Gen7 \*****************************************************************************/ static const SMediaStateInterfaceDescriptorData::_DW5::_Gen7 g_cInitMediaStateInterfaceDescriptorDataDW5Gen7 = { 0, // NumberOfThreadsInThreadGroup 0, // _Unused1 0, // SharedLocalMemorySize false, // BarrierEnable GFX3DSTATE_ROUNDING_MODE_ROUND_TO_NEAREST_EVEN, // RoundingMode 0 // _Unused2 }; /*****************************************************************************\ CONST: g_cInitMediaStateInterfaceDescriptorDataDW1Gen8 \*****************************************************************************/ static const SMediaStateInterfaceDescriptorData::_DW1::_Gen8 g_cInitMediaStateInterfaceDescriptorDataDW1Gen8 = { 0, // Kernel64bitStartingPointer 0 // _Unused }; /*****************************************************************************\ CONST: g_cInitMediaStateInterfaceDescriptorDataDW2Gen8 \*****************************************************************************/ static const SMediaStateInterfaceDescriptorData::_DW2::_Gen8 g_cInitMediaStateInterfaceDescriptorDataDW2Gen8 = { 0, // _Unused1 false, // SoftwareExceptionEnable 0, // _Unused2 false, // MaskStackExceptionEnable 0, // _Unused3 false, // IllegalOpcodeExceptionEnable 0, // _Unused4 GFXMEDIASTATE_FLOATING_POINT_IEEE_754, // FloatingPointMode GFXMEDIASTATE_THREAD_PRIORITY_NORMAL, // ThreadPriority true, // SingleProgramFlow 0, // DenormMode 0 // _Unused5 }; /*****************************************************************************\ CONST: g_cInitMediaStateInterfaceDescriptorDataDW3Gen8 \*****************************************************************************/ static const SMediaStateInterfaceDescriptorData::_DW3::_Gen8 g_cInitMediaStateInterfaceDescriptorDataDW3Gen8 = { 0, // _Unused 0, // SamplerCount 0 // SamplerStatePointer }; /*****************************************************************************\ CONST: g_cInitMediaStateInterfaceDescriptorDataDW4Gen8 \*****************************************************************************/ static const SMediaStateInterfaceDescriptorData::_DW4::_Gen8 g_cInitMediaStateInterfaceDescriptorDataDW4Gen8 = { 0, // BindingTableEntryCount 0, // BindingTablePointer 0 // _Unused }; /*****************************************************************************\ CONST: g_cInitMediaStateInterfaceDescriptorDataDW5Gen8 \*****************************************************************************/ static const SMediaStateInterfaceDescriptorData::_DW5::_Gen8 g_cInitMediaStateInterfaceDescriptorDataDW5Gen8 = { 0, // ConstantURBEntryReadOffset 0 // ConstantURBEntryReadLength }; /*****************************************************************************\ CONST: g_cInitMediaStateMediaInterfaceDescriptorLoad \*****************************************************************************/ static const SMediaStateMediaInterfaceDescriptorLoad g_cInitMediaStateMediaInterfaceDescriptorLoad = { // DW0 { { OP_LENGTH( SIZE32( SMediaStateMediaInterfaceDescriptorLoad ) ), // Length GFXSUBOP_MEDIA_INTERFACE_DESCRIPTOR_LOAD, // InstructionSubOpcode GFXOP_MEDIA, // InstructionOpcode PIPE_MEDIA, // InstructionSubType INSTRUCTION_GFX // InstructionType } }, // DW1 { 0 // Reserved }, // DW2 { { 0, // InterfaceDescriptorTotalLength 0 // _Unused } }, // DW3 { { 0 // InterfaceDescriptorDataStartAddress } } }; /*****************************************************************************\ CONST: g_cInitMediaStateMediaVFEState \*****************************************************************************/ static const SMediaStateMediaVFEState g_cInitMediaStateMediaVFEState = { // DW0 { { OP_LENGTH( SIZE32( SMediaStateMediaVFEState ) ),// Length GFXSUBOP_MEDIA_VFE_STATE, // InstructionSubOpcode GFXOP_MEDIA, // InstructionOpcode PIPE_MEDIA, // InstructionSubType INSTRUCTION_GFX // InstructionType } }, // DW1 { { 0, // PerThreadScratchSpace 0, // StackSize 0, // _Unused 0 // ScratchSpaceBasePointer } }, // DW2 { { GFXMEDIASTATE_DEBUG_COUNTER_FREE_RUNNING, // DebugCounterControl 0, // _Unused false, // FastPreempt false, // BypassGatewayControl false, // ResetGatewayTimer 0, // NumberOfURBEntries 0 // MaximumNumberOfThreads } }, // DW3 { { 0, // _Unused 0 // ObjectId } }, // DW4 { { 0, // CURBEAllocationSize 0 // URBEntryAllocationSize } }, // DW5 { { 0, // ScoreboardMask 0, // _Unused GFXMEDIASTATE_STALLING_SCOREBOARD, // ScoreboardType false // ScoreboardEnable } }, // DW6 { { 0, // ScoreboardDeltaX0 0, // ScoreboardDeltaY0 0, // ScoreboardDeltaX1 0, // ScoreboardDeltaY1 0, // ScoreboardDeltaX2 0, // ScoreboardDeltaY2 0, // ScoreboardDeltaX3 0 // ScoreboardDeltaY3 } }, // DW7 { { 0, // ScoreboardDeltaX4 0, // ScoreboardDeltaY4 0, // ScoreboardDeltaX5 0, // ScoreboardDeltaY5 0, // ScoreboardDeltaX6 0, // ScoreboardDeltaY6 0, // ScoreboardDeltaX7 0 // ScoreboardDeltaY7 } }, // DW8 { { 0, // ScoreboardDeltaX4 0, // ScoreboardDeltaY4 0, // ScoreboardDeltaX5 0, // ScoreboardDeltaY5 0, // ScoreboardDeltaX6 0, // ScoreboardDeltaY6 0, // ScoreboardDeltaX7 0 // ScoreboardDeltaY7 } } }; /*****************************************************************************\ CONST: g_cInitMediaStateMediaVFEStateDW2Gen7 \*****************************************************************************/ static const SMediaStateMediaVFEState::_DW2::_Gen7 g_cInitMediaStateMediaVFEStateDW2Gen7 = { GFXMEDIASTATE_DEBUG_COUNTER_FREE_RUNNING, // DebugCounterControl GFXMEDIASTATE_GPGPU_MODE_GPGPU, // GPGPUMode GFXMEDIASTATE_MMIO_ACCESS_CONTROL_ANY_READWRITE, // GatewayMMIOAccessControl false, // FastPreempt false, // BypassGatewayControl false, // ResetGatewayTimer 0, // NumberOfURBEntries 0 // MaximumNumberOfThreads }; /*****************************************************************************\ CONST: g_cInitMediaStateMediaVFEStateDW3Gen9 \*****************************************************************************/ static const SMediaStateMediaVFEState::_DW3::_Gen9 g_cInitMediaStateMediaVFEStateDW3Gen9 = { GFXMEDIASTATE_DEBUG_COUNTER_FREE_RUNNING, // DebugCounterControl GFXMEDIASTATE_SLM_GRANULARITY_4K, // GFXMEDIASTATE_SLM_GRANULARITY GFXMEDIASTATE_MMIO_ACCESS_CONTROL_ANY_READWRITE, // GatewayMMIOAccessControl 0, // _Unused false, // BypassGatewayControl false, // ResetGatewayTimer 0, // NumberOfURBEntries 0 // MaximumNumberOfThreads }; /*****************************************************************************\ CONST: g_cInitMediaStateMediaCURBELoad \*****************************************************************************/ static const SMediaStateMediaCURBELoad g_cInitMediaStateMediaCURBELoad = { // DW0 { { OP_LENGTH( SIZE32( SMediaStateMediaCURBELoad ) ), // Length GFXSUBOP_MEDIA_CURBE_LOAD, // InstructionSubOpcode GFXOP_MEDIA, // InstructionOpcode PIPE_MEDIA, // InstructionSubType INSTRUCTION_GFX // InstructionType } }, // DW1 { 0 }, // DW2 { { 0, // CURBETotalDataLength 0 // _Unused } }, // DW3 { { 0 // CURBEDataStartAddress } }, }; /*****************************************************************************\ CONST: g_cInitMediaStateMediaStateFlush \*****************************************************************************/ static const SMediaStateMediaStateFlush g_cInitMediaStateMediaStateFlush = { // DW0 { { OP_LENGTH( SIZE32( SMediaStateMediaStateFlush ) ), // Length GFXSUBOP_MEDIA_STATE_FLUSH, // InstructionSubOpcode GFXOP_MEDIA, // InstructionOpcode PIPE_MEDIA, // InstructionSubType INSTRUCTION_GFX // InstructionType } }, // DW1 { { 0, // BarrierMask 0, // ThreadCountWaterMark 0 // _Unused } } }; /*****************************************************************************\ CONST: g_cInitMediaStateMediaStateFlushDW1Gen7 \*****************************************************************************/ static const SMediaStateMediaStateFlush::_DW1::_Gen7 g_cInitMediaStateMediaStateFlushDW1Gen7 = { 0, // InterfaceDescriptorOffset false, // ThreadCountWaterMark 0, // _Unused }; /*****************************************************************************\ CONST: g_cInitMediaStateGPGPUWalker \*****************************************************************************/ static const SMediaStateGPGPUWalker g_cInitMediaStateGPGPUWalker = { // DW0 { { OP_LENGTH( SIZE32( SMediaStateGPGPUWalker ) ), // Length false, // PredicateEnable 0, // _Unused1 false, // IndirectParameterEnable 0, // _Unused2 GFXSUBOP_MEDIA_GPGPU_WALKER, // InstructionSubOpcode GFXOP_NONPIPELINED, // InstructionOpcode PIPE_MEDIA, // InstructionSubType INSTRUCTION_GFX // InstructionType } }, // DW1 { { 0, // InterfaceDescriptorOffset 0, // _Unused 0 // ObjectId } }, // DW2 { { 0, // ThreadWidthCounterMaximum 0, // _Unused1 0, // ThreadHeightCounterMaximum 0, // _Unused2 0, // ThreadDepthCounterMaximum 0, // _Unused3 GFXMEDIASTATE_GPGPU_WALKER_SIMD16 // SIMDSize } }, // DW3 { { 0 // ThreadGroupIdStartingX } }, // DW4 { { 0 // ThreadGroupIdDimensionX } }, // DW5 { { 0 // ThreadGroupIdStartingY } }, // DW6 { { 0 // ThreadGroupIdDimensionY } }, // DW7 { { 0 // ThreadGroupIdStartingZ } }, // DW8 { { 0 // ThreadGroupIdDimensionZ } }, // DW9 { { 0 // RightExecutionMask } }, // DW10 { { 0 // BottomExecutionMask } }, // DW11 { { 0 // ThreadGroupIdStartingResumeZ } }, // DW12 { { 0 // ThreadGroupIdDimensionZ } }, // DW13 { { 0 // RightExecutionMask } }, // DW14 { { 0 // BottomExecutionMask } } }; } // namespace G6HWC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_mi_def_g8.h000066400000000000000000001022151363533017100266060ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_mi_enum_g6.h" // Set packing alignment to a single byte #pragma pack(1) namespace G6HWC { /*****************************************************************************\ STRUCT: SMIARBCheck (MI_ARB_CHECK) \*****************************************************************************/ struct SMIARBCheck { // DWORD 0 union _DW0 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIARBCheck) == 1); /*****************************************************************************\ STRUCT: SMIARBOnOff (MI_ARB_ON_OFF) \*****************************************************************************/ struct SMIARBOnOff { // DWORD 0 union _DW0 { struct _All { DWORD ArbitrationEnable : BITFIELD_BIT(0); // bool DWORD _Unused : BITFIELD_RANGE(1,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIARBOnOff) == 1); /*****************************************************************************\ STRUCT: SMIBatchBufferEnd (MI_BATCH_BUFFER_END) \*****************************************************************************/ struct SMIBatchBufferEnd { // DWORD 0 union _DW0 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIBatchBufferEnd) == 1); /*****************************************************************************\ STRUCT: SMIBatchBufferStart (MI_BATCH_BUFFER_START) \*****************************************************************************/ struct SMIBatchBufferStart { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused1 : BITFIELD_RANGE(6,7); // DWORD BufferSecurityIndicator : BITFIELD_BIT(8); // MI_BUFFER_SECURITY_INDICATOR DWORD _Unused2 : BITFIELD_RANGE(9,22); //DWORD CommandArbitrationControl : BITFIELD_RANGE(9,10); // MI_COMMAND_ARBITRATION_CONTROL //DWORD ClearCommandBufferEnable : BITFIELD_BIT(11); // bool //DWORD _Unused3 : BITFIELD_RANGE(12,22); // DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,1); DWORD BufferStartAddress : BITFIELD_RANGE(2,31); // GTT[31:6] | PHYS[31:6] } All; DWORD Value; } DW1; }; static_assert(SIZE32(SMIBatchBufferStart) == 2); /*****************************************************************************\ STRUCT: SMIDisplayFlip (MI_DISPLAY_FLIP) \*****************************************************************************/ struct SMIDisplayFlip { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(6,19); DWORD DisplayPlaneSelect : BITFIELD_RANGE(20,21); // MI_DISPLAY_PLANE_SELECT DWORD AsynchronousFlip : BITFIELD_BIT(22); // MI_ASYNCHRONOUS_FLIP DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD _Unused1 : BITFIELD_RANGE(0,2); DWORD DisplayBufferPitch : BITFIELD_RANGE(3,14); // U12 DWORD _Unused2 : BITFIELD_RANGE(15,28); DWORD FlipQueueSelect : BITFIELD_BIT(29); // MI_FLIP_QUEUE_SELECT DWORD _Unused3 : BITFIELD_RANGE(30,31); } All; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD TileParameter : BITFIELD_BIT(0); // MI_TILE_PARAMETER DWORD _Unused : BITFIELD_RANGE(1,11); DWORD DisplayBufferBaseAddress : BITFIELD_RANGE(12,31); // GTT[31:12] } All; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD PipeVerticalSourceImageResize : BITFIELD_RANGE(0,11); // U32 TODO: TODO: TODO: ?ok? really u32... how? DWORD _Unused1 : BITFIELD_RANGE(12,15); // U32 TODO: TODO: TODO: ?ok? really u32... how? DWORD PipeHorizontalSourceImageSize : BITFIELD_RANGE(16,27); DWORD _Unused2 : BITFIELD_RANGE(28,29); DWORD PanelFitterSelect : BITFIELD_BIT(30); // MI_PANEL_FITTER DWORD EnablePanelFitter : BITFIELD_BIT(31); // bool } All; DWORD Value; } DW3; }; static_assert(SIZE32(SMIDisplayFlip) == 4); /*****************************************************************************\ STRUCT: SMIFlush (MI_FLUSH) \*****************************************************************************/ struct SMIFlush { // DWORD 0 union _DW0 { struct _All { DWORD _Unused1 : BITFIELD_BIT(0); DWORD StateCacheInvalidate : BITFIELD_BIT(1); // bool DWORD RenderCacheFlushInhibit : BITFIELD_BIT(2); // bool DWORD GlobalSnapshotCountReset : BITFIELD_BIT(3); // bool DWORD GenericMediaStateClear : BITFIELD_BIT(4); // bool DWORD IndirectStatePointerDisable : BITFIELD_BIT(5); // bool DWORD ProtectedMemoryEnable : BITFIELD_BIT(6); // bool DWORD _Unused2 : BITFIELD_RANGE(7,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIFlush) == 1); /*****************************************************************************\ STRUCT: SMILoadRegisterImmediate (MI_LOAD_REGISTER_IMM) \*****************************************************************************/ struct SMILoadRegisterImmediate { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused1 : BITFIELD_RANGE(6,7); DWORD Byte0WriteDisable : BITFIELD_BIT(8); // bool DWORD Byte1WriteDisable : BITFIELD_BIT(9); // bool DWORD Byte2WriteDisable : BITFIELD_BIT(10); // bool DWORD Byte3WriteDisable : BITFIELD_BIT(11); // bool DWORD _Unused2 : BITFIELD_RANGE(12,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,1); DWORD RegisterOffset : BITFIELD_RANGE(2,31); // MMIO_OFFSET[31:2] } All; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD DataDWord; } All; DWORD Value; } DW2; }; static_assert(SIZE32(SMILoadRegisterImmediate) == 3); /*****************************************************************************\ STRUCT: SMILoadScanLinesExclusive (MI_LOAD_SCAN_LINES_EXCL) \*****************************************************************************/ struct SMILoadScanLinesExclusive { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused1 : BITFIELD_RANGE(6,19); DWORD DisplayPipeSelect : BITFIELD_RANGE(20,21); // MI_DISPLAY_PIPE_SELECT DWORD _Unused2 : BITFIELD_BIT(22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { WORD EndScanLineNumber; // U16 WORD StartScanLineNumber; // U16 } All; DWORD Value; } DW1; }; static_assert(SIZE32(SMILoadScanLinesExclusive) == 2); /*****************************************************************************\ STRUCT: SMILoadScanLinesInclusive (MI_LOAD_SCAN_LINES_INCL) \*****************************************************************************/ struct SMILoadScanLinesInclusive { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused1 : BITFIELD_RANGE(6,19); DWORD DisplayPipeSelect : BITFIELD_RANGE(20,21); // MI_DISPLAY_PIPE_SELECT DWORD _Unused2 : BITFIELD_BIT(22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { WORD EndScanLineNumber; // U16 WORD StartScanLineNumber; // U16 } All; DWORD Value; } DW1; }; static_assert(SIZE32(SMILoadScanLinesInclusive) == 2); /*****************************************************************************\ STRUCT: SMINoop (MI_NOOP) \*****************************************************************************/ struct SMINoop { // DWORD 0 union _DW0 { struct _All { DWORD IdentificationNumber : BITFIELD_RANGE(0,21); // DWORD DWORD IdentificationNumberRegisterWriteEnable : BITFIELD_BIT(22); // bool DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMINoop) == 1); /*****************************************************************************\ STRUCT: SMIOverlayFlip (MI_OVERLAY_FLIP) \*****************************************************************************/ struct SMIOverlayFlip { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(6,20); DWORD ModeFlags : BITFIELD_RANGE(21,22); // MI_MODE_FLAGS DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD OverlayFilterCoefficientRegisterUpdateFlag : BITFIELD_BIT(0); // bool DWORD _Unused : BITFIELD_RANGE(1,11); DWORD RegisterAndCoefficientUpdateAddress : BITFIELD_RANGE(12,31); // GTT[31:13] } All; DWORD Value; } DW1; }; static_assert(SIZE32(SMIOverlayFlip) == 2); /*****************************************************************************\ STRUCT: SMIProbeHeader (MI_PROBE) \*****************************************************************************/ struct SMIProbeHeader { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,9); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(10,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIProbeHeader) == 1); /*****************************************************************************\ STRUCT: SMIProbeState (MI_PROBE) \*****************************************************************************/ struct SMIProbeState { // DWORD 0 union _DW0 { struct _All { DWORD SlotNumber : BITFIELD_RANGE(0,9); // bool DWORD _Unused : BITFIELD_RANGE(10,11); DWORD SurfacePageBaseAddress : BITFIELD_RANGE(12,31); // GTT[31:13] } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIProbeState) == 1); /*****************************************************************************\ STRUCT: SMIProbe (MI_PROBE) \*****************************************************************************/ struct SMIProbe { SMIProbeHeader Header; SMIProbeState Probe[g_cNumProbes]; }; /*****************************************************************************\ STRUCT: SMIReportHead (MI_REPORT_HEAD) \*****************************************************************************/ struct SMIReportHead { // DWORD 0 union _DW0 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIReportHead) == 1); /*****************************************************************************\ STRUCT: SMIReportNonCE (MI_REPORT_NONCE) \*****************************************************************************/ struct SMIReportNonCE { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(6,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD NonCEValue; // U32 } All; DWORD Value; } DW1; }; static_assert(SIZE32(SMIReportNonCE) == 2); /*****************************************************************************\ STRUCT: SMISemaphoreMBox (MI_SEMAPHORE_MBOX) \*****************************************************************************/ struct SMISemaphoreMBox { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(6,18); DWORD CommandBufferTerminateEnable : BITFIELD_BIT(19); // bool DWORD CompareSemaphore : BITFIELD_BIT(20); // bool DWORD UpdateSemaphore : BITFIELD_BIT(21); // bool DWORD UseGlobalGTT : BITFIELD_BIT(22); // MI_MEMORY_USE_GLOBAL_GTT DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD SemaphoreData; // U32 } All; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,1); DWORD PointerBitFieldName : BITFIELD_RANGE(2,31); // GTT[31:13] } All; DWORD Value; } DW2; }; static_assert(SIZE32(SMISemaphoreMBox) == 3); /*****************************************************************************\ STRUCT: SMISetContext (MI_SET_CONTEXT) \*****************************************************************************/ struct SMISetContext { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(6,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD RestoreInhibit : BITFIELD_BIT(0); // bool DWORD ForceRestore : BITFIELD_BIT(1); // bool DWORD ExtendedStateRestoreEnable : BITFIELD_BIT(2); // bool DWORD ExtendedStateSaveEnable : BITFIELD_BIT(3); // bool DWORD PhysicalStartAddressExtension : BITFIELD_RANGE(4,7); // PHYS[35:32] DWORD MemorySpaceSelect : BITFIELD_BIT(8); // MI_MEMORY_ADDRESS_TYPE DWORD HDDVDContext : BITFIELD_BIT(9); // MI_MEMORY_HD_DVD_CONTEXT DWORD _Unused : BITFIELD_RANGE(10,11); DWORD LogicalContextAddress : BITFIELD_RANGE(12,31); // GTT[31:11] | PHYS[31:11] } All; DWORD Value; } DW1; }; static_assert(SIZE32(SMISetContext) == 2); /*****************************************************************************\ STRUCT: SMIStoreDataImmediate (MI_STORE_DATA_IMM) \*****************************************************************************/ struct SMIStoreDataImmediate { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(6,21); DWORD UseGlobalGTT : BITFIELD_BIT(22); // MI_MEMORY_USE_GLOBAL_GTT DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; union _QW1 { // QWORD 1 union _QW { struct _All { QWORD : BITFIELD_RANGE(0,3); // QWORD : BITFIELD_RANGE(4,31); QWORD : BITFIELD_RANGE(32,33); QWORD Address : BITFIELD_RANGE(34,63); // GTT[31:2] | PHYS[35:2] } All; QWORD Value; } QW; // DWORD 1 struct _DW1 { DWORD Value; } DW1; // DWORD 2 struct _DW2 { DWORD Value; } DW2; } QW1; union _QW2 { // QWORD 1 union _QW { struct _All { QWORD Data; } All; QWORD Value; } QW; // DWORD 2 struct _DW3 { DWORD Value; } DW3; // DWORD 3 struct _DW4 { DWORD Value; } DW4; } QW2; }; static_assert(SIZE32(SMIStoreDataImmediate) == 5); /*****************************************************************************\ STRUCT: SMIStoreDataIndexed (MI_STORE_DATA_INDEX) \*****************************************************************************/ struct SMIStoreDataIndexed { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused1 : BITFIELD_RANGE(6,20); DWORD UsePerProcessHardwareStatusPage : BITFIELD_BIT(21); // bool DWORD _Unused2 : BITFIELD_BIT(22); // DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD _Unused1 : BITFIELD_RANGE(0,1); DWORD Offset : BITFIELD_RANGE(2,11); // U10 DWORD _Unused2 : BITFIELD_RANGE(12,31); } All; DWORD Value; } DW1; union _QW2 { // QWORD 1 struct _All { QWORD Data; } All; // DWORD 2 struct _DW2 { DWORD Value; } DW2; // DWORD 3 struct _DW3 { DWORD Value; } DW3; } QW2; }; static_assert(SIZE32(SMIStoreDataIndexed) == 4); /*****************************************************************************\ STRUCT: SMIStoreRegisterMemory (MI_STORE_REGISTER_MEM) \*****************************************************************************/ struct SMIStoreRegisterMemory { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(6,21); DWORD UseGlobalGTT : BITFIELD_BIT(22); // MI_MEMORY_USE_GLOBAL_GTT DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD _Unused1 : BITFIELD_RANGE(0,1); DWORD RegisterAddress : BITFIELD_RANGE(2,25); // OFFSET[25:2] DWORD _Unused2 : BITFIELD_RANGE(26,31); } All; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,1); DWORD MemoryAddress : BITFIELD_RANGE(2,31); // GTT[31:2] } All; DWORD Value; } DW2; }; static_assert(SIZE32(SMIStoreRegisterMemory) == 3); /*****************************************************************************\ STRUCT: SMIUpdateGTTHeader (MI_UPDATE_GTT) \*****************************************************************************/ struct SMIUpdateGTTHeader { // DWORD 0 union _DW0 { struct _All { DWORD Length : BITFIELD_RANGE(0,5); // OP_LENGTH DWORD _Unused : BITFIELD_RANGE(6,21); DWORD EntryType : BITFIELD_BIT(22); // MI_MEMORY_UPDATE_GTT_ENTRY DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,11); DWORD EntryAddress : BITFIELD_RANGE(12,31); // GTT[31:2] } All; DWORD Value; } DW1; }; static_assert(SIZE32(SMIUpdateGTTHeader) == 2); /*****************************************************************************\ STRUCT: SMIUpdateGTTState (MI_UPDATE_GTT) \*****************************************************************************/ struct SMIUpdateGTTState { // DWORD 0 union _DW0 { struct _All { DWORD EntryData; // PPGTT Table Entry } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIUpdateGTTState) == 1); /*****************************************************************************\ STRUCT: SMIUpdateGTT (MI_UPDATE_GTT) \*****************************************************************************/ struct SMIUpdateGTT { SMIUpdateGTTHeader Header; SMIUpdateGTTState GTTState[g_cNumGTTUpdateEntries]; }; /*****************************************************************************\ STRUCT: SMIUnProbe (MI_UNPROBE) \*****************************************************************************/ struct SMIUnProbe { // DWORD 0 union _DW0 { struct _All { DWORD SlotNumber : BITFIELD_RANGE(0,9); // ProbeSlotIndex DWORD _Unused : BITFIELD_RANGE(10,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIUnProbe) == 1); /*****************************************************************************\ STRUCT: SMIUserInterrupt (MI_USER_INTERRUPT) \*****************************************************************************/ struct SMIUserInterrupt { // DWORD 0 union _DW0 { struct _All { DWORD _Unused : BITFIELD_RANGE(0,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIUserInterrupt) == 1); /*****************************************************************************\ STRUCT: SMIWaitForEvent (MI_WAIT_FOR_EVENT) \*****************************************************************************/ struct SMIWaitForEvent { // DWORD 0 union _DW0 { struct _All { DWORD WaitForBlitterEngine : BITFIELD_BIT(0); // bool DWORD WaitForVideoEngine : BITFIELD_BIT(1); // bool DWORD DisplayPlaneAFlipPendingWaitEnable : BITFIELD_BIT(2); // bool DWORD DisplayPipeAVerticalBlankWaitEnable : BITFIELD_BIT(3); // bool DWORD FrameBufferCompressionIdleWaitEnable : BITFIELD_BIT(4); // bool DWORD DisplayPipeBScanLineWindowWaitEnable : BITFIELD_BIT(5); // bool DWORD DisplayPlaneBFlipPendingWaitEnable : BITFIELD_BIT(6); // bool DWORD DisplayPipeBVerticalBlankWaitEnable : BITFIELD_BIT(7); // bool DWORD DisplaySpriteAFlipPendingWaitEnable : BITFIELD_BIT(8); // bool DWORD ConditionCodeWaitSelect : BITFIELD_RANGE(9,12); // MI_CONDITION_CODE_WAIT_SELECT DWORD DisplayPipeAHBlankWaitEnable : BITFIELD_BIT(13); // bool DWORD DisplayPipeBHBlankWaitEnable : BITFIELD_BIT(14); // bool DWORD _Unused1 : BITFIELD_BIT(15); DWORD DisplaySpriteBFlipPendingWaitEnable : BITFIELD_BIT(16); // bool DWORD DisplayPipeAStartVBlankWaitEnable : BITFIELD_BIT(17); // bool DWORD DisplayPipeBStartVBlankWaitEnable : BITFIELD_BIT(18); // bool DWORD _Unused2 : BITFIELD_RANGE(19,22); DWORD InstructionOpcode : BITFIELD_RANGE(23,28); // MI_OPCODE DWORD InstructionType : BITFIELD_RANGE(29,31); // INSTRUCTION_TYPE } All; DWORD Value; } DW0; }; static_assert(SIZE32(SMIWaitForEvent) == 1); } //namespace G6HWC // Reset packing alignment to project default #pragma pack() intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_mi_enum_g8.h000066400000000000000000000224721363533017100270220ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_enum_g6.h" namespace G6HWC { /*****************************************************************************\ CONST: Caps \*****************************************************************************/ const DWORD g_cNumProbes = 1024; const DWORD g_cNumGTTUpdateEntries = 16; /*****************************************************************************\ ENUM: MI_OPCODE \*****************************************************************************/ enum MI_OPCODE { MI_NOOP = 0x00, MI_USER_INTERRUPT = 0x02, MI_WAIT_FOR_EVENT = 0x03, MI_FLUSH = 0x04, MI_ARB_CHECK = 0x05, MI_UNPROBE = 0x06, MI_REPORT_HEAD = 0x07, MI_ARB_ON_OFF = 0x08, MI_URB_WRITE = 0x09, MI_BATCH_BUFFER_END = 0x0A, MI_PREDICATE = 0x0C, MI_TOPOLOGY_FILTER = 0x0D, MI_OVERLAY_FLIP = 0x11, MI_LOAD_SCAN_LINES_INCL = 0x12, MI_LOAD_SCAN_LINES_EXCL = 0x13, MI_DISPLAY_FLIP = 0x14, MI_SEMAPHORE_MBOX = 0x16, MI_SET_CONTEXT = 0x18, MI_REPORT_NONCE = 0x19, MI_STORE_DATA_IMM = 0x20, MI_STORE_DATA_INDEX = 0x21, MI_LOAD_REGISTER_IMM = 0x22, MI_UPDATE_GTT = 0x23, MI_STORE_REGISTER_MEM = 0x24, MI_PROBE = 0x25, MI_LOAD_REGISTER_MEM = 0x29, MI_BATCH_BUFFER_START = 0x31 }; /*****************************************************************************\ ENUM: MI_ASYNCHRONOUS_FLIP \*****************************************************************************/ enum MI_ASYNCHRONOUS_FLIP { MI_SYNCHRONOUS_FLIP = 0x0, MI_ASYNCHRONOUS_FLIP = 0x1 }; /*****************************************************************************\ ENUM: MI_BUFFER_SECURITY_INDICATOR \*****************************************************************************/ enum MI_BUFFER_SECURITY_INDICATOR { MI_BUFFER_SECURE = 0x0, MI_BUFFER_NONSECURE = 0x1 }; /*****************************************************************************\ ENUM: MI_COMMAND_ARBITRATION_CONTROL \*****************************************************************************/ enum MI_COMMAND_ARBITRATION_CONTROL { MI_ARBITRATE_AT_CHAIN_POINTS = 0x0, MI_ARBITRATE_BETWEEN_INSTS = 0x1, MI_NO_ARBITRATION = 0x3 }; /*****************************************************************************\ ENUM: MI_CONDITION_CODE_WAIT_SELECT \*****************************************************************************/ enum MI_CONDITION_CODE_WAIT_SELECT { MI_CONDITION_CODE_WAIT_DISABLED = 0x0, MI_CONDITION_CODE_WAIT_0 = 0x1, MI_CONDITION_CODE_WAIT_1 = 0x2, MI_CONDITION_CODE_WAIT_2 = 0x3, MI_CONDITION_CODE_WAIT_3 = 0x4, MI_CONDITION_CODE_WAIT_4 = 0x5 }; /*****************************************************************************\ ENUM: MI_DISPLAY_PIPE_SELECT \*****************************************************************************/ enum MI_DISPLAY_PIPE_SELECT { MI_DISPLAY_PIPE_A = 0x0, MI_DISPLAY_PIPE_B = 0x1 }; /*****************************************************************************\ ENUM: MI_DISPLAY_PLANE_SELECT \*****************************************************************************/ enum MI_DISPLAY_PLANE_SELECT { MI_DISPLAY_PLANE_A = 0x0, MI_DISPLAY_PLANE_B = 0x1, MI_DISPLAY_PLANE_C = 0x2 }; /*****************************************************************************\ ENUM: MI_FLIP_QUEUE_SELECT \*****************************************************************************/ enum MI_FLIP_QUEUE_SELECT { MI_STANDARD_FLIP = 0x0, MI_ENQUEUE_FLIP_PERFORM_BASE_FRAME_NUMBER_LOAD = 0x1, MI_ENQUEUE_FLIP_TARGET_FRAME_NUMBER_RELATIVE = 0x2, MI_ENQUEUE_FLIP_ABSOLUTE_TARGET_FRAME_NUMBER = 0x3 }; /*****************************************************************************\ ENUM: MI_MEMORY_HD_DVD_CONTEXT \*****************************************************************************/ enum MI_MEMORY_HD_DVD_CONTEXT { MI_REGULAR_CONTEXT = 0x0, MI_HD_DVD_CONTEXT = 0x1 }; /*****************************************************************************\ ENUM: MI_MEMORY_ADDRESS_TYPE \*****************************************************************************/ enum MI_MEMORY_ADDRESS_TYPE { MI_PHYSICAL_ADDRESS = 0x0, MI_VIRTUAL_ADDRESS = 0x1 }; /*****************************************************************************\ ENUM: MI_MEMORY_SPACE_SELECT \*****************************************************************************/ enum MI_MEMORY_SPACE_SELECT { MI_BUFFER_MEMORY_MAIN = 0x0, MI_BUFFER_MEMORY_GTT = 0x2, MI_BUFFER_MEMORY_PER_PROCESS_GTT = 0x3 }; /*****************************************************************************\ ENUM: MI_MEMORY_UPDATE_GTT \*****************************************************************************/ enum MI_MEMORY_UPDATE_GTT_ENTRY { MI_MEMORY_GGTT_ENTRY_UPDATE = 0x0, MI_MEMORY_PGTT_ENTRY_UPDATE = 0x1 }; /*****************************************************************************\ ENUM: MI_MEMORY_USE_GLOBAL_GTT \*****************************************************************************/ enum MI_MEMORY_USE_GLOBAL_GTT { MI_MEMORY_PER_PROCESS_GRAPHICS_ADDRESS = 0x0, MI_MEMORY_GLOBAL_GRAPHICS_ADDRESS = 0x1 }; /*****************************************************************************\ ENUM: MI_MODE_FLAGS \*****************************************************************************/ enum MI_MODE_FLAGS { MI_FLIP_CONTINUE = 0x0, MI_FLIP_ON = 0x1, MI_FLIP_OFF = 0x2 }; /*****************************************************************************\ ENUM: MI_PANEL_FITTER \*****************************************************************************/ enum MI_PANEL_FITTER { MI_PANEL_7X5_CAPABLE = 0x0, MI_PANEL_3X3_CAPABLE = 0x1 }; /*****************************************************************************\ ENUM: MI_REGISTER_SPACE_SELECT \*****************************************************************************/ enum MI_REGISTER_SPACE_SELECT { MI_UNTRUSTED_REGISTER_SPACE = 0x0, MI_TRUSTED_REGISTER_SPACE = 0x1 }; /*****************************************************************************\ ENUM: MI_TILE_PARAMETER \*****************************************************************************/ enum MI_TILE_PARAMETER { MI_TILE_LINEAR = 0x0, MI_TILE_TILEDX = 0x1 }; /*****************************************************************************\ ENUM: MI_PREDICATE_COMPAREOP \*****************************************************************************/ enum MI_PREDICATE_COMPAREOP { MI_PREDICATE_COMPAREOP_TRUE = 0x0, MI_PREDICATE_COMPAREOP_FALSE = 0x1, MI_PREDICATE_COMPAREOP_SRCS_EQUAL = 0x2, MI_PREDICATE_COMPAREOP_DELTAS_EQUAL = 0x3 }; /*****************************************************************************\ ENUM: MI_PREDICATE_COMBINEOP \*****************************************************************************/ enum MI_PREDICATE_COMBINEOP { MI_PREDICATE_COMBINEOP_SET = 0x0, MI_PREDICATE_COMBINEOP_AND = 0x1, MI_PREDICATE_COMBINEOP_OR = 0x2, MI_PREDICATE_COMBINEOP_XOR = 0x3 }; /*****************************************************************************\ ENUM: MI_PREDICATE_LOADOP \*****************************************************************************/ enum MI_PREDICATE_LOADOP { MI_PREDICATE_LOADOP_KEEP = 0x0, MI_PREDICATE_LOADOP_LOAD = 0x2, MI_PREDICATE_LOADOP_LOADINV = 0x3 }; } //namespace G6HWCintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_mi_init_g8.h000066400000000000000000000550431363533017100270210ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_mi_enum_g6.h" #include "cmd_mi_def_g6.h" namespace G6HWC { /*****************************************************************************\ CONST: g_cInitMIARBCheck \*****************************************************************************/ const SMIARBCheck g_cInitMIARBCheck = { // DWORD 0 { 0, // _Unused MI_ARB_CHECK, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitMIArbOnOff \*****************************************************************************/ const SMIARBOnOff g_cInitMIArbOnOff = { // DWORD 0 { false, // ArbitrationEnable 0, // _Unused MI_ARB_ON_OFF, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitMIBatchBufferEnd \*****************************************************************************/ const SMIBatchBufferEnd g_cInitMIBatchBufferEnd = { // DWORD 0 { 0, // _Unused MI_BATCH_BUFFER_END, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitMIBatchBufferStart \*****************************************************************************/ const SMIBatchBufferStart g_cInitMIBatchBufferStart = { // DWORD 0 { OP_LENGTH( SIZE32( SMIBatchBufferStart) ), // Length 0, // _Unused1 MI_BUFFER_SECURE, // BufferSecurityIndicator 0, // _Unused2 //MI_NO_ARBITRATION, // CommandArbitrationControl //false, // ClearCommandBufferEnable //0, // _Unused3 MI_BATCH_BUFFER_START, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0, // _Unused 0 // BufferStartAddress } }; /*****************************************************************************\ CONST: g_cInitMIDisplayFlip \*****************************************************************************/ const SMIDisplayFlip g_cInitMIDisplayFlip = { // DWORD 0 { OP_LENGTH( SIZE32( SMIDisplayFlip ) ), // Length 0, // _Unused MI_DISPLAY_PLANE_A, // DisplayPlaneSelect MI_SYNCHRONOUS_FLIP, // AsynchronousFlip MI_DISPLAY_FLIP, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0, // _Unused1 0, // DisplayBufferPitch 0, // _Unused2 MI_STANDARD_FLIP, // FlipQueueSelect 0 // _Unused3 }, // DWORD 2 { MI_TILE_LINEAR, // TileParameter 0, // _Unused 0 // DisplayBufferBaseAddress }, // DWORD 3 { 0, // PipeVerticalSourceImageResize 0, // _Unused1 0, // PipeHorizontalSourceImageSize 0, // _Unused2 MI_PANEL_7X5_CAPABLE, // PanelFitterSelect false, // EnablePanelFitter } }; /*****************************************************************************\ CONST: g_cInitMIFlush \*****************************************************************************/ const SMIFlush g_cInitMIFlush = { // DWORD 0 { 0, // _Unused1 false, // StateCacheInvalidate true, // RenderCacheFlushInhibit false, // GlobalSnapshotCountReset false, // MediaPersistentRootThreadComplete false, // IndirectStatePointersDisable true, // ProtectedMemory 0, // _Unused2 MI_FLUSH, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitMILoadRegisterImmediate \*****************************************************************************/ const SMILoadRegisterImmediate g_cInitMILoadRegisterImmediate = { // DWORD 0 { OP_LENGTH( SIZE32( SMILoadRegisterImmediate ) ), // Length 0, // _Unused1 false, // Byte0WriteDisable false, // Byte1WriteDisable false, // Byte2WriteDisable false, // Byte3WriteDisable 0, // _Unused2 MI_LOAD_REGISTER_IMM, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0, // _Unused 0 // RegisterOffset }, // DWORD 2 { 0 // DataDWord } }; /*****************************************************************************\ CONST: g_cInitMILoadScanLinesExcl \*****************************************************************************/ const SMILoadScanLinesExclusive g_cInitMILoadScanLinesExcl = { // DWORD 0 { OP_LENGTH( SIZE32( SMILoadScanLinesExclusive ) ), // Length 0, // _Unused1 MI_DISPLAY_PIPE_A, // DisplayPipeSelect 0, // _Unused2 MI_LOAD_SCAN_LINES_EXCL, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0, // EndScanLineNumber 0 // StartScanLineNumber } }; /*****************************************************************************\ CONST: g_cInitMILoadScanLinesIncl \*****************************************************************************/ const SMILoadScanLinesInclusive g_cInitMILoadScanLinesIncl = { // DWORD 0 { OP_LENGTH( SIZE32( SMILoadScanLinesInclusive ) ), // Length 0, // _Unused1 MI_DISPLAY_PIPE_A, // DisplayPipeSelect 0, // _Unused2 MI_LOAD_SCAN_LINES_INCL, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0, // EndScanLineNumber 0 // StartScanLineNumber } }; /*****************************************************************************\ CONST: g_cInitMINoop \*****************************************************************************/ const SMINoop g_cInitMINoop = { // DWORD 0 { 0, // IdentificationNumber false, // IdentificationNumberRegisterWriteEnable MI_NOOP, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitOverlayFlip \*****************************************************************************/ const SMIOverlayFlip g_cInitOverlayFlip = { // DWORD 0 { OP_LENGTH( SIZE32( SMIOverlayFlip ) ), // Length 0, // _Unused MI_FLIP_CONTINUE, // ModeFlags MI_OVERLAY_FLIP, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { false, // OverlayFilterCoefficientRegisterUpdateFlag 0, // _Unused 0 // RegisterAndCoefficientUpdateAddress } }; /*****************************************************************************\ CONST: g_cInitMIProbeHeader \*****************************************************************************/ const SMIProbeHeader g_cInitMIProbeHeader = { // DWORD 0 { OP_LENGTH( SIZE32( SMIProbeHeader ) ), // Length //TODO TODO: ?ok? length = smiprobeheader + smiprobestate * num probes? 0, // _Unused MI_PROBE, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitMIReportHead \*****************************************************************************/ const SMIReportHead g_cInitMIReportHead = { // DWORD 0 { 0, // _Unused MI_REPORT_HEAD, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitMIReportNonCE \*****************************************************************************/ const SMIReportNonCE g_cInitMIReportNonCE = { // DWORD 0 { OP_LENGTH( SIZE32( SMIReportNonCE ) ), // Length 0, // _Unused MI_REPORT_NONCE, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0 // NonCEValue } }; /*****************************************************************************\ CONST: g_cInitMISemaphoreMBox \*****************************************************************************/ const SMISemaphoreMBox g_cInitMISemaphoreMBox = { // DWORD 0 { OP_LENGTH( SIZE32( SMISemaphoreMBox ) ), // Length 0, // _Unused false, // CommandBufferTerminateEnable false, // CompareSemaphore false, // UpdateSemaphore MI_MEMORY_PER_PROCESS_GRAPHICS_ADDRESS, // UseGlobalGTT MI_SEMAPHORE_MBOX, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0 // SemaphoreData }, // DWORD 2 { 0, // _Unused 0 // PointerBitFieldName } }; /*****************************************************************************\ CONST: g_cInitMISetContext \*****************************************************************************/ const SMISetContext g_cInitMISetContext = { // DWORD 0 { OP_LENGTH( SIZE32( SMISetContext ) ), // Length 0, // _Unused MI_SET_CONTEXT, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { false, // RestoreInhibit false, // ForceRestore false, // ExtendedStateRestoreEnable false, // ExtendedStateSaveEnable 0, // PhysicalStartAddressExtension MI_PHYSICAL_ADDRESS, // MemorySpaceSelect MI_REGULAR_CONTEXT, // HDDVDContext 0, // _Unused 0 // LogicalContextAddress } }; /*****************************************************************************\ CONST: g_cInitMIStoreDataImm \*****************************************************************************/ const SMIStoreDataImmediate g_cInitMIStoreDataImm = { // DWORD 0 { OP_LENGTH( SIZE32( SMIStoreDataImmediate ) ), // Length 0, // _Unused MI_VIRTUAL_ADDRESS, // MemoryAddressType MI_STORE_DATA_IMM, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // QWORD 1 { 0 // Address }, // QWORD 2 { 0 // Data } }; /*****************************************************************************\ CONST: g_cInitMIStoreDataIndex \*****************************************************************************/ const SMIStoreDataIndexed g_cInitMIStoreDataIndex = { // DWORD 0 { OP_LENGTH( SIZE32( SMIStoreDataIndexed ) ), // Length 0, // _Unused1 false, // UsePerProcessHardwareStatusPage 0, // _Unused2 MI_STORE_DATA_INDEX, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0, // _Unused1 0, // Offset 0 // _Unused2 }, // QWORD 1 { 0 // Data } }; /*****************************************************************************\ CONST: g_cInitMIStoreRegisterMem \*****************************************************************************/ const SMIStoreRegisterMemory g_cInitMIStoreRegisterMem = { // DWORD 0 { OP_LENGTH( SIZE32( SMIStoreRegisterMemory ) ), // Length 0, // _Unused MI_MEMORY_PER_PROCESS_GRAPHICS_ADDRESS, // UseGlobalGTT MI_STORE_REGISTER_MEM, // InstructionOpcode INSTRUCTION_MI // InstructionType }, // DWORD 1 { 0, // _Unused1 0, // RegisterAddress 0 // _Unused2 }, // DWORD 2 { 0, // _Unused 0 // MemoryAddress } }; /*****************************************************************************\ CONST: g_cInitMIUpdateGTTHeader \*****************************************************************************/ const SMIUpdateGTTHeader g_cInitMIUpdateGTTHeader = { // DWORD 0 { OP_LENGTH( SIZE32( SMIUpdateGTTHeader ) + SIZE32(SMIUpdateGTTState) * g_cNumGTTUpdateEntries), // Length 0, // _Unused MI_MEMORY_GGTT_ENTRY_UPDATE, // EntryType MI_UPDATE_GTT, // InstructionOpcode INSTRUCTION_MI // InstructionType }, //DWORD 1 { 0, // _Unused 0 // EntryAddress } }; /*****************************************************************************\ CONST: g_cInitMIUnProbe \*****************************************************************************/ const SMIUnProbe g_cInitMIUnProbe = { // DWORD 0 { 0, // SlotNumber 0, // _Unused MI_UNPROBE, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitMIUserInterrupt \*****************************************************************************/ const SMIUserInterrupt g_cInitMIUserInterrupt = { // DWORD 0 { 0, // _Unused MI_USER_INTERRUPT, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; /*****************************************************************************\ CONST: g_cInitMIWaitForEvent \*****************************************************************************/ const SMIWaitForEvent g_cInitMIWaitForEvent = { // DWORD 0 { false, // WaitForBlitterEngine false, // WaitForVideoEngine false, // DisplayPlaneAFlipPendingWaitEnable false, // DisplayPipeAVerticalBlankWaitEnable false, // FrameBufferCompressionIdleWaitEnable false, // DisplayPipeBScanLineWindowWaitEnable false, // DisplayPlaneBFlipPendingWaitEnable false, // DisplayPipeBVerticalBlankWaitEnable false, // DisplaySpriteAFlipPendingWaitEnable MI_CONDITION_CODE_WAIT_DISABLED, // ConditionCodeWaitSelect false, // DisplayPipeBHBlankWaitEnable false, // DisplayPipeAHBlankWaitEnable false, // DisplayPipeBHBlankWaitEnable 0, // _Unused1 false, // DisplaySpriteBFlipPendingWaitEnable 0, // _Unused2 false, // DisplayPipeBStartVBlankWaitEnable MI_WAIT_FOR_EVENT, // InstructionOpcode INSTRUCTION_MI // InstructionType } }; } // namespace G6HWC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_parser_g8.cpp000066400000000000000000001301731363533017100272160ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "IGC/common/igc_debug.h" #include "../sp/sp_types.h" #include "../sp/sp_debug.h" #include "../inc/common/igfxfmid.h" #include "cmd_shared_def_g8.h" #include "cmd_media_def_g8.h" #include "cmd_media_caps_g8.h" #include "cmd_shared_enum_g8.h" #include "cmd_media_init_g8.h" #include "IGC/common/igc_regkeys.hpp" #include "Probe.h" namespace G6HWC { template __forceinline float FixedToFloat( Type fixed, const int whole, const int fractional ) { IGC_ASSERT( fractional + whole <= 32 ); float value = (float)fixed / (float)( 1 << fractional ); return value; } /*****************************************************************************\ Helper functions \*****************************************************************************/ inline bool IsPlatformValid( const PLATFORM productID) { if (productID.eRenderCoreFamily <= IGFX_GEN12LP_CORE) { return true; } return false; } /*****************************************************************************\ \*****************************************************************************/ void DebugSurfaceStateCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ) { #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) if (IGC_IS_FLAG_ENABLED(DumpPatchTokens)) { SSharedStateSurfaceState* p3DStateSurfaceState = (SSharedStateSurfaceState*)pLinearAddress; if (productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "SURFACE_STATE = { %08x, %08x, %08x, %08x, %08x, %08x, %08X, %08X }\n", p3DStateSurfaceState->DW0.Value, p3DStateSurfaceState->DW1.Value, p3DStateSurfaceState->DW2.Value, p3DStateSurfaceState->DW3.Value, p3DStateSurfaceState->DW4.Value, p3DStateSurfaceState->DW5.Value, p3DStateSurfaceState->DW6.Value, p3DStateSurfaceState->DW7.Value); } else if (productID.eRenderCoreFamily == IGFX_GEN8_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "SURFACE_STATE = { %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x }\n", p3DStateSurfaceState->DW0.Value, p3DStateSurfaceState->DW1.Value, p3DStateSurfaceState->DW2.Value, p3DStateSurfaceState->DW3.Value, p3DStateSurfaceState->DW4.Value, p3DStateSurfaceState->DW5.Value, p3DStateSurfaceState->DW6.Value, p3DStateSurfaceState->DW7.Value, p3DStateSurfaceState->DW8.Value, p3DStateSurfaceState->DW9.Value, p3DStateSurfaceState->DW10.Value, p3DStateSurfaceState->DW11.Value, p3DStateSurfaceState->DW12.Value); } else if (productID.eRenderCoreFamily >= IGFX_GEN9_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "SURFACE_STATE = { %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x}\n", p3DStateSurfaceState->DW0.Value, p3DStateSurfaceState->DW1.Value, p3DStateSurfaceState->DW2.Value, p3DStateSurfaceState->DW3.Value, p3DStateSurfaceState->DW4.Value, p3DStateSurfaceState->DW5.Value, p3DStateSurfaceState->DW6.Value, p3DStateSurfaceState->DW7.Value, p3DStateSurfaceState->DW8.Value, p3DStateSurfaceState->DW9.Value, p3DStateSurfaceState->DW10.Value, p3DStateSurfaceState->DW11.Value, p3DStateSurfaceState->DW12.Value, p3DStateSurfaceState->DW13.Value, p3DStateSurfaceState->DW14.Value, p3DStateSurfaceState->DW15.Value); } else { // Unsupported platform IGC_ASSERT(0); } // DWORD 0 if (productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceType : %x\n", p3DStateSurfaceState->DW0.Gen7.SurfaceType); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceArray : %x\n", p3DStateSurfaceState->DW0.Gen7.SurfaceArray); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceFormat : %x\n", p3DStateSurfaceState->DW0.Gen7.SurfaceFormat); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tVerticalLineStride : %u\n", p3DStateSurfaceState->DW0.Gen7.VerticalLineStride); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tVerticalLineStrideOffset : %u\n", p3DStateSurfaceState->DW0.Gen7.VerticalLineStrideOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRenderCacheReadWriteMode : %x\n", p3DStateSurfaceState->DW0.Gen7.RenderCacheReadWriteMode); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMediaBoundaryPixelMode : %x\n", p3DStateSurfaceState->DW0.Gen7.MediaBoundaryPixelMode); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesNegativeX : %x\n", p3DStateSurfaceState->DW0.Gen7.CubeFaceEnablesNegativeX); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesPositiveX : %x\n", p3DStateSurfaceState->DW0.Gen7.CubeFaceEnablesPositiveX); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesNegativeY : %x\n", p3DStateSurfaceState->DW0.Gen7.CubeFaceEnablesNegativeY); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesPositiveY : %x\n", p3DStateSurfaceState->DW0.Gen7.CubeFaceEnablesPositiveY); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesNegativeZ : %x\n", p3DStateSurfaceState->DW0.Gen7.CubeFaceEnablesNegativeZ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesPositiveZ : %x\n", p3DStateSurfaceState->DW0.Gen7.CubeFaceEnablesPositiveZ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceArraySpacing : %u\n", p3DStateSurfaceState->DW0.Gen7.SurfaceArraySpacing); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTiledSurface : %x\n", p3DStateSurfaceState->DW0.Gen7.TiledSurface); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTileWalk : %x\n", p3DStateSurfaceState->DW0.Gen7.TileWalk); } else if ((productID.eRenderCoreFamily >= IGFX_GEN8_CORE) && IsPlatformValid(productID)) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceType : %x\n", p3DStateSurfaceState->DW0.Gen8.SurfaceType); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceArray : %x\n", p3DStateSurfaceState->DW0.Gen8.SurfaceArray); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceFormat : %x\n", p3DStateSurfaceState->DW0.Gen8.SurfaceFormat); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceVerticalAlignment : %u\n", p3DStateSurfaceState->DW0.Gen8.SurfaceVerticalAlignment); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceHorizontalAlignment : %u\n", p3DStateSurfaceState->DW0.Gen8.SurfaceHorizontalAlignment); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTileMode : %u\n", p3DStateSurfaceState->DW0.Gen8.TileMode); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tVerticalLineStride : %u\n", p3DStateSurfaceState->DW0.Gen8.VerticalLineStride); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tVerticalLineStrideOffset : %u\n", p3DStateSurfaceState->DW0.Gen8.VerticalLineStrideOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRenderCacheReadWriteMode : %x\n", p3DStateSurfaceState->DW0.Gen8.RenderCacheReadWriteMode); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMediaBoundaryPixelMode : %x\n", p3DStateSurfaceState->DW0.Gen8.MediaBoundaryPixelMode); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesNegativeX : %x\n", p3DStateSurfaceState->DW0.Gen8.CubeFaceEnablesNegativeX); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesPositiveX : %x\n", p3DStateSurfaceState->DW0.Gen8.CubeFaceEnablesPositiveX); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesNegativeY : %x\n", p3DStateSurfaceState->DW0.Gen8.CubeFaceEnablesNegativeY); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesPositiveY : %x\n", p3DStateSurfaceState->DW0.Gen8.CubeFaceEnablesPositiveY); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesNegativeZ : %x\n", p3DStateSurfaceState->DW0.Gen8.CubeFaceEnablesNegativeZ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeFaceEnablesPositiveZ : %x\n", p3DStateSurfaceState->DW0.Gen8.CubeFaceEnablesPositiveZ); if (productID.eRenderCoreFamily >= IGFX_GEN9_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tASTCEnable : %x\n", p3DStateSurfaceState->DW0.Gen9.ASTCEnable); } } else { // Unsupported platform IGC_ASSERT(0); } // DWORD 1 if (productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceBaseAddress : %x\n", p3DStateSurfaceState->DW1.All.SurfaceBaseAddress); } else if ((productID.eRenderCoreFamily >= IGFX_GEN8_CORE) && IsPlatformValid(productID)) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceQPitch : %x\n", p3DStateSurfaceState->DW1.Gen8.SurfaceQPitch); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceObjectAgeControl : %x\n", p3DStateSurfaceState->DW1.Gen8.SurfaceObjectAgeControl); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceObjectEncryptedDataEnable: %x\n", p3DStateSurfaceState->DW1.Gen8.SurfaceObjectEncryptedDataEnable); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceObjectTargetCache : %x\n", p3DStateSurfaceState->DW1.Gen8.SurfaceObjectTargetCache); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceObjectCacheabilityControl: %x\n", p3DStateSurfaceState->DW1.Gen8.SurfaceObjectCacheabilityControl); } else { // Unsupported platform IGC_ASSERT(0); } if (productID.eRenderCoreFamily >= IGFX_GEN7_CORE && IsPlatformValid(productID)) { // DWORD 2 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tHeight : %u\n", p3DStateSurfaceState->DW2.Gen7.Height); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tWidth : %u\n", p3DStateSurfaceState->DW2.Gen7.Width); // DWORD 3 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDepth : %u\n", p3DStateSurfaceState->DW3.Gen7.Depth); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfacePitch : %u\n", p3DStateSurfaceState->DW3.Gen7.SurfacePitch); // DWORD 4 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMinimumArrayElement : %u\n", p3DStateSurfaceState->DW4.Gen7.SurfaceAll.MinimumArrayElement); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfacePitch : %x\n", p3DStateSurfaceState->DW4.Gen7.SurfaceAll.MultisampledSurfaceStorageFormat); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMultisamplePositionPaletteIndex : %u\n", p3DStateSurfaceState->DW4.Gen7.SurfaceAll.MultisamplePositionPaletteIndex); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tNumMultisamples : %u\n", p3DStateSurfaceState->DW4.Gen7.SurfaceAll.NumMultisamples); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRenderTargetRotation : %x\n", p3DStateSurfaceState->DW4.Gen7.SurfaceAll.RenderTargetRotation); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRenderTargetViewExtent : %x\n", p3DStateSurfaceState->DW4.Gen7.SurfaceAll.RenderTargetViewExtent); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceStrBufMinimumArrayElement: %u\n", p3DStateSurfaceState->DW4.Gen7.SurfaceStrBuf.MinimumArrayElement); // DWORD 5 if (productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMipCountLOD : %u\n", p3DStateSurfaceState->DW5.Gen7.MipCountLOD); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceMinLOD : %u\n", p3DStateSurfaceState->DW5.Gen7.SurfaceMinLOD); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tXOffset : %u\n", p3DStateSurfaceState->DW5.Gen7.XOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tYOffset : %u\n", p3DStateSurfaceState->DW5.Gen7.YOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceEncryptedDataEnable : %x\n", p3DStateSurfaceState->DW5.Gen7.SurfaceEncryptedDataEnable); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceGraphicsDataType : %u\n", p3DStateSurfaceState->DW5.Gen7.SurfaceGraphicsDataType); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCacheabilityControlL3 : %x\n", p3DStateSurfaceState->DW5.Gen7.CacheabilityControlL3); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCacheabilityControlLLC : %x\n", p3DStateSurfaceState->DW5.Gen7.CacheabilityControlLLC); } else if (productID.eRenderCoreFamily >= IGFX_GEN8_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMipCountLOD : %u\n", p3DStateSurfaceState->DW5.Gen8.MipCountLOD); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceMinLOD : %u\n", p3DStateSurfaceState->DW5.Gen8.SurfaceMinLOD); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tYOffset : %u\n", p3DStateSurfaceState->DW5.Gen8.YOffset); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tXOffset : %u\n", p3DStateSurfaceState->DW5.Gen8.XOffset); if (productID.eRenderCoreFamily >= IGFX_GEN9_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTiledResourceEnable : %u\n", p3DStateSurfaceState->DW5.Gen9.TiledResourceEnable); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTiledResourceHorizontalAlignment: %u\n", p3DStateSurfaceState->DW5.Gen9.TiledResourceHorizontalAlignment); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTiledResourceVerticalAlignment : %u\n", p3DStateSurfaceState->DW5.Gen9.TiledResourceVerticalAlignment); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMipTailStartLOD : %u\n", p3DStateSurfaceState->DW5.Gen9.MipTailStartLOD); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCoherencyType : %u\n", p3DStateSurfaceState->DW5.Gen9.CoherencyType); } } // DWORD6 if (productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE || productID.eRenderCoreFamily == IGFX_GEN8_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMCSEnable : %x\n", p3DStateSurfaceState->DW6.Gen7.SurfaceMCS.MCSEnable); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMCSBaseAddress : %u\n", p3DStateSurfaceState->DW6.Gen7.SurfaceMCS.MCSBaseAddress); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMCSSurfacePitch : %u\n", p3DStateSurfaceState->DW6.Gen7.SurfaceMCS.MCSSurfacePitch); } else if (productID.eRenderCoreFamily >= IGFX_GEN9_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAuxiliarySurfaceMode : %x\n", p3DStateSurfaceState->DW6.Gen9.SurfaceOther.AuxiliarySurfaceMode); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRenderTargetCompressionEnable : %x\n", p3DStateSurfaceState->DW6.Gen9.SurfaceOther.RenderTargetCompressionEnable); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAuxiliarySurfacePitch : %x\n", p3DStateSurfaceState->DW6.Gen9.SurfaceOther.AuxiliarySurfacePitch); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAuxilarySurfaceQPitch : %x\n", p3DStateSurfaceState->DW6.Gen9.SurfaceOther.AuxilarySurfaceQPitch); } // DWORD7 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tResourceMinLOD : %u\n", p3DStateSurfaceState->DW7.Gen7.ResourceMinLOD); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tClearColorRed : %x\n", p3DStateSurfaceState->DW7.Gen7.ClearColorRed); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tClearColorGreen : %x\n", p3DStateSurfaceState->DW7.Gen7.ClearColorGreen); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tClearColorBlue : %x\n", p3DStateSurfaceState->DW7.Gen7.ClearColorBlue); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tClearColorAlpha : %x\n", p3DStateSurfaceState->DW7.Gen7.ClearColorAlpha); if (productID.eRenderCoreFamily >= IGFX_GEN7_5_CORE) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tShaderChannelSelectAlpha : %x\n", p3DStateSurfaceState->DW7.Gen7_5.ShaderChannelSelectAlpha); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tShaderChannelSelectBlue : %x\n", p3DStateSurfaceState->DW7.Gen7_5.ShaderChannelSelectBlue); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tShaderChannelSelectGreen : %x\n", p3DStateSurfaceState->DW7.Gen7_5.ShaderChannelSelectGreen); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tShaderChannelSelectRed : %x\n", p3DStateSurfaceState->DW7.Gen7_5.ShaderChannelSelectRed); } if (productID.eRenderCoreFamily >= IGFX_GEN8_CORE) { // DWORD 8 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurfaceBaseAddress : %x\n", p3DStateSurfaceState->DW8.Gen8.SurfaceBaseAddress); // DWORD 9 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSurface64bitBaseAddress : %x\n", p3DStateSurfaceState->DW9.Gen8.Surface64bitBaseAddress); // DWORD 10 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAuxiliarySurfaceBaseAddress : %x\n", p3DStateSurfaceState->DW10.Gen8.AuxiliarySurfaceBaseAddress); // DWORD 11 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAuxiliary64bitBaseAddress : %x\n", p3DStateSurfaceState->DW11.Gen8.Auxiliary64bitBaseAddress); if (productID.eRenderCoreFamily == IGFX_GEN8_CORE) { // DWORD 12 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tHierarchicalDepthClearValue : %x\n", p3DStateSurfaceState->DW12.Gen8.HierarchicalDepthClearValue); } else { // DWORD 12 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRedClearColor : %x\n", p3DStateSurfaceState->DW12.Gen9.RedClearColor); // DWORD 13 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tGreenClearColor : %x\n", p3DStateSurfaceState->DW13.Gen9.GreenClearColor); // DWORD 14 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBlueClearColor : %x\n", p3DStateSurfaceState->DW14.Gen9.BlueClearColor); // DWORD 15 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAlphaClearColor : %x\n", p3DStateSurfaceState->DW15.Gen9.AlphaClearColor); } } } else { // Unsupported platform IGC_ASSERT(0); } } #endif } /*****************************************************************************\ \*****************************************************************************/ void DebugInterfaceDescriptorDataCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ) { #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) SMediaStateInterfaceDescriptorData* pInterfaceDescriptorData = (SMediaStateInterfaceDescriptorData*)pLinearAddress; if( productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "INTERFACE_DESCRIPTOR_DATA = { %08x, %08x, %08x, %08x, %08x, %08x }\n", pInterfaceDescriptorData->DW0.Value, pInterfaceDescriptorData->DW1.Value, pInterfaceDescriptorData->DW2.Value, pInterfaceDescriptorData->DW3.Value, pInterfaceDescriptorData->DW4.Value, pInterfaceDescriptorData->DW5.Value ); } else if( productID.eRenderCoreFamily >= IGFX_GEN8_CORE && IsPlatformValid( productID ) ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "INTERFACE_DESCRIPTOR_DATA = { %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x }\n", pInterfaceDescriptorData->DW0.Value, pInterfaceDescriptorData->DW1.Value, pInterfaceDescriptorData->DW2.Value, pInterfaceDescriptorData->DW3.Value, pInterfaceDescriptorData->DW4.Value, pInterfaceDescriptorData->DW5.Value, pInterfaceDescriptorData->DW6.Value, pInterfaceDescriptorData->DW7.Value ); } else { // Unsupported platform IGC_ASSERT(0); } // DWORD 0 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tKernelStartPointer = : %u\n", pInterfaceDescriptorData->DW0.All.KernelStartPointer); if( productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE ) { // DWORD 1 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSoftwareExceptionEnable = : %u\n", pInterfaceDescriptorData->DW1.All.SoftwareExceptionEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMaskStackExceptionEnable = : %u\n", pInterfaceDescriptorData->DW1.All.MaskStackExceptionEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tIllegalOpcodeExceptionEnable = : %u\n", pInterfaceDescriptorData->DW1.All.IllegalOpcodeExceptionEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tFloatingPointMode = : %x\n", pInterfaceDescriptorData->DW1.All.FloatingPointMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tThreadPriority = : %x\n", pInterfaceDescriptorData->DW1.All.ThreadPriority ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSingleProgramFlow = : %x\n", pInterfaceDescriptorData->DW1.All.SingleProgramFlow ); // DWORD 2 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSamplerCount = : %u\n", pInterfaceDescriptorData->DW2.All.SamplerCount ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSamplerStatePointer = : %x\n", pInterfaceDescriptorData->DW2.All.SamplerStatePointer ); // DWORD 3 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBindingTableEntryCount = : %u\n", pInterfaceDescriptorData->DW3.All.BindingTableEntryCount ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBindingTablePointer = : %x\n", pInterfaceDescriptorData->DW3.All.BindingTablePointer ); // DWORD 4 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantURBEntryReadOffset = : %u\n", pInterfaceDescriptorData->DW4.All.ConstantURBEntryReadOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantURBEntryReadLength = : %u\n", pInterfaceDescriptorData->DW4.All.ConstantURBEntryReadLength ); // DWORD 5 if ( productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tNumberOfThreadsInThreadGroup = : %u\n", pInterfaceDescriptorData->DW5.Gen7.NumberOfThreadsInThreadGroup ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSharedLocalMemorySize = : %u\n", pInterfaceDescriptorData->DW5.Gen7.SharedLocalMemorySize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBarrierEnable = : %x\n", pInterfaceDescriptorData->DW5.Gen7.BarrierEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRoundingMode = : %x\n", pInterfaceDescriptorData->DW5.Gen7.RoundingMode ); } // DWORD 6 if( productID.eRenderCoreFamily == IGFX_GEN7_5_CORE ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCrossThreadConstantDataReadLength : %u\n", pInterfaceDescriptorData->DW6.Gen7_5.CrossThreadConstantDataReadLength ); } } else if( productID.eRenderCoreFamily >= IGFX_GEN8_CORE && IsPlatformValid( productID ) ) { // DWORD 1 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tKernel64bitStartPointer = : %u\n", pInterfaceDescriptorData->DW1.Gen8.Kernel64bitStartPointer); // DWORD 2 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSoftwareExceptionEnable = : %u\n", pInterfaceDescriptorData->DW2.Gen8.SoftwareExceptionEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMaskStackExceptionEnable = : %u\n", pInterfaceDescriptorData->DW2.Gen8.MaskStackExceptionEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tIllegalOpcodeExceptionEnable = : %u\n", pInterfaceDescriptorData->DW2.Gen8.IllegalOpcodeExceptionEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tFloatingPointMode = : %x\n", pInterfaceDescriptorData->DW2.Gen8.FloatingPointMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tThreadPriority = : %x\n", pInterfaceDescriptorData->DW2.Gen8.ThreadPriority ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSingleProgramFlow = : %x\n", pInterfaceDescriptorData->DW2.Gen8.SingleProgramFlow ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tDenormMode = : %u\n", pInterfaceDescriptorData->DW2.Gen8.DenormMode ); // DWORD 3 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSamplerCount = : %u\n", pInterfaceDescriptorData->DW3.Gen8.SamplerCount ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSamplerStatePointer = : %u\n", pInterfaceDescriptorData->DW3.Gen8.SamplerStatePointer ); // DWORD 4 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBindingTableEntryCount = : %u\n", pInterfaceDescriptorData->DW4.Gen8.BindingTableEntryCount ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBindingTablePointer = : %u\n", pInterfaceDescriptorData->DW4.Gen8.BindingTablePointer ); // DWORD 5 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantURBEntryReadOffset = : %u\n", pInterfaceDescriptorData->DW5.Gen8.ConstantURBEntryReadOffset ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tConstantURBEntryReadLength = : %u\n", pInterfaceDescriptorData->DW5.Gen8.ConstantURBEntryReadLength ); // DWORD 6 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tNumberOfThreadsInThreadGroup = : %u\n", pInterfaceDescriptorData->DW6.Gen8.NumberOfThreadsInThreadGroup ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tGlobalBarrierEnable = : %u\n", pInterfaceDescriptorData->DW6.Gen8.GlobalBarrierEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSharedLocalMemorySize = : %u\n", pInterfaceDescriptorData->DW6.Gen8.SharedLocalMemorySize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBarrierEnable = : %u\n", pInterfaceDescriptorData->DW6.Gen8.BarrierEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRoundingMode = : %u\n", pInterfaceDescriptorData->DW6.Gen8.RoundingMode ); // DWORD 7 ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCrossThreadConstantDataReadLength : %u\n", pInterfaceDescriptorData->DW7.Gen8.CrossThreadConstantDataReadLength ); } else { // Unsupported platform IGC_ASSERT(0); } #endif } /*****************************************************************************\ \*****************************************************************************/ void DebugSamplerIndirectStateCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ) { #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) SGfxSamplerIndirectState* pSamplerBorderColor = (SGfxSamplerIndirectState*)pLinearAddress; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "SAMPLER_INDIRECT_STATE\n" ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBorderColorRed : %f\n", pSamplerBorderColor->BorderColorRed); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBorderColorGreen : %f\n", pSamplerBorderColor->BorderColorGreen); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBorderColorBlue : %f\n", pSamplerBorderColor->BorderColorBlue); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBorderColorAlpha : %f\n", pSamplerBorderColor->BorderColorAlpha); #endif } /*****************************************************************************\ \*****************************************************************************/ void DebugSamplerStateCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ) { #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) SSharedStateSamplerState* p3DStateSamplerState = (SSharedStateSamplerState*)pLinearAddress; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "SAMPLER_STATE = { %08x, %08x, %08x, %08x }\n", p3DStateSamplerState->DW0.Value, p3DStateSamplerState->DW1.Value, p3DStateSamplerState->DW2.Value, p3DStateSamplerState->DW3.Value ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSamplerDisable : %x\n", p3DStateSamplerState->DW0.All.SamplerDisable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTextureBorderColorMode : %x\n", p3DStateSamplerState->DW0.All.TextureBorderColorMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLODPreClampEnable : %x\n", p3DStateSamplerState->DW0.All.LODPreClampEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMipModeFilter : %x\n", p3DStateSamplerState->DW0.All.MipModeFilter ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMagModeFilter : %x\n", p3DStateSamplerState->DW0.All.MagModeFilter ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMinModeFilter : %x\n", p3DStateSamplerState->DW0.All.MinModeFilter ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTextureLODBias : %f\n", FixedToFloat( p3DStateSamplerState->DW0.All.TextureLODBias, 4, 4 ) ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tShadowFunction : %x\n", p3DStateSamplerState->DW0.All.ShadowFunction ); if ( productID.eRenderCoreFamily >= IGFX_GEN9_CORE && IsPlatformValid( productID ) ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tAnisotropicAlgorithm : %x\n", p3DStateSamplerState->DW0.Gen9.AnisotropicAlgorithm ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCoarseLODQualityMode : %f\n", FixedToFloat( p3DStateSamplerState->DW0.Gen9.CoarseLODQualityMode, 5, 5) ); } else { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBaseMipLevel : %f\n", FixedToFloat( p3DStateSamplerState->DW0.All.BaseMipLevel, 4, 1 ) ); } ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMinLOD : %f\n", FixedToFloat( p3DStateSamplerState->DW1.All.MinLOD, 4, 6 ) ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMaxLOD : %f\n", FixedToFloat( p3DStateSamplerState->DW1.All.MaxLOD, 4, 6 ) ); if( productID.eRenderCoreFamily >= IGFX_GEN7_CORE && IsPlatformValid( productID ) ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tCubeSurfaceControlMode : %x\n", p3DStateSamplerState->DW1.Gen7.CubeSurfaceControlMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMaxLOD : %f\n", FixedToFloat(p3DStateSamplerState->DW1.Gen7.MaxLOD, 4, 8 ) ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMinLOD : %f\n", FixedToFloat(p3DStateSamplerState->DW1.Gen7.MinLOD, 4, 8 ) ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tShadowFunction : %x\n", p3DStateSamplerState->DW1.Gen7.ShadowFunction ); if( productID.eRenderCoreFamily >= IGFX_GEN8_CORE ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tChromaKeyMode : %x\n", p3DStateSamplerState->DW1.Gen8.ChromaKeyMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tChromaKeyIndex : %x\n", p3DStateSamplerState->DW1.Gen8.ChromaKeyIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tChromaKeyEnable : %x\n", p3DStateSamplerState->DW1.Gen8.ChromaKeyEnable ); } } else { // Unsupported platform IGC_ASSERT(0); } if( productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tBorderColorPointer : %x\n", p3DStateSamplerState->DW2.All.BorderColorPointer ); } else if( productID.eRenderCoreFamily >= IGFX_GEN8_CORE && IsPlatformValid( productID ) ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tLODClampMagnificationMode : %x\n", p3DStateSamplerState->DW2.Gen8.All.LODClampMagnificationMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tFlexibleFilterVerticalAlignment : %x\n", p3DStateSamplerState->DW2.Gen8.All.FlexibleFilterVerticalAlignment ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tFlexibleFilterHorizontalAlignment : %x\n", p3DStateSamplerState->DW2.Gen8.All.FlexibleFilterHorizontalAlignment ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tFlexibleFilterCoefficientSize : %x\n", p3DStateSamplerState->DW2.Gen8.All.FlexibleFilterCoefficientSize ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tFlexibleFilterCoefficientSize : %x\n", p3DStateSamplerState->DW2.Gen8.All.FlexibleFilterMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tIndirectStatePointer : %x\n", p3DStateSamplerState->DW2.Gen8.All.IndirectStatePointer ); switch( p3DStateSamplerState->DW2.Gen8.All.FlexibleFilterMode ) { case G6HWC::GFXSHAREDSTATE_FLEXFILTERMODE_SEP: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSeparableFilterHeight : %x\n", p3DStateSamplerState->DW2.Gen8.FlexibleFilterSeparable.SeparableFilterHeight ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSeparableFilterWidth : %x\n", p3DStateSamplerState->DW2.Gen8.FlexibleFilterSeparable.SeparableFilterWidth ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tSeparableFilterCoefficientTableSize : %x\n", p3DStateSamplerState->DW2.Gen8.FlexibleFilterSeparable.SeparableFilterCoefficientTableSize ); break; case G6HWC::GFXSHAREDSTATE_FLEXFILTERMODE_NONSEP: ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tNonSeparableFilterFootprintMask : %x\n", p3DStateSamplerState->DW2.Gen8.FlexibleFilterNonSeparable.NonSeparableFilterFootprintMask ); break; default: // Unknown flexible filter mode. IGC_ASSERT(0); break; } } else { // Unsupported platform IGC_ASSERT(0); } if( productID.eRenderCoreFamily >= IGFX_GEN7_CORE && IsPlatformValid( productID ) ) { if( productID.eRenderCoreFamily == IGFX_GEN7_CORE || productID.eRenderCoreFamily == IGFX_GEN7_5_CORE ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tChromaKeyEnable : %x\n", p3DStateSamplerState->DW3.Gen7.ChromaKeyEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tChromaKeyIndex : %u\n", p3DStateSamplerState->DW3.Gen7.ChromaKeyIndex ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tChromaKeyMode : %x\n", p3DStateSamplerState->DW3.Gen7.ChromaKeyMode ); } else { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tNonSeparableFilterFootprintMask : %x\n", p3DStateSamplerState->DW3.Gen8.NonSeparableFilterFootprintMask ); } ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tMaximumAnisotropy : %x\n", p3DStateSamplerState->DW3.Gen7.MaximumAnisotropy ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tUAddressMagFilterAddressRoundingEnable : %x\n", p3DStateSamplerState->DW3.Gen7.UAddressMagFilterAddressRoundingEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tUAddressMinFilterAddressRoundingEnable : %x\n", p3DStateSamplerState->DW3.Gen7.UAddressMinFilterAddressRoundingEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tVAddressMagFilterAddressRoundingEnable : %x\n", p3DStateSamplerState->DW3.Gen7.VAddressMagFilterAddressRoundingEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tVAddressMinFilterAddressRoundingEnable : %x\n", p3DStateSamplerState->DW3.Gen7.VAddressMinFilterAddressRoundingEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRAddressMagFilterAddressRoundingEnable : %x\n", p3DStateSamplerState->DW3.Gen7.RAddressMagFilterAddressRoundingEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tRAddressMinFilterAddressRoundingEnable : %x\n", p3DStateSamplerState->DW3.Gen7.RAddressMinFilterAddressRoundingEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tNonNormalizedCoordinatesEnable : %x\n", p3DStateSamplerState->DW3.Gen7.NonNormalizedCoordinateEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTrilinearFilterQuality : %x\n", p3DStateSamplerState->DW3.Gen7.TrilinearFilterQuality ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTCXAddressControlMode : %x\n", p3DStateSamplerState->DW3.Gen7.TCXAddressControlMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTCYAddressControlMode : %x\n", p3DStateSamplerState->DW3.Gen7.TCYAddressControlMode ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tTCZAddressControlMode : %x\n", p3DStateSamplerState->DW3.Gen7.TCZAddressControlMode ); if ( productID.eRenderCoreFamily >= IGFX_GEN9_CORE ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tReductionTypeEnable : %x\n", p3DStateSamplerState->DW3.Gen9.ReductionTypeEnable ); ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tReductionType : %x\n", p3DStateSamplerState->DW3.Gen9.ReductionType ); } } else { // Unsupported platform IGC_ASSERT(0); } #endif } void DebugBindingTableStateCommand( const void* pLinearAddress, const DWORD numBindingTableEntries, const PLATFORM productID, std::string &output) { #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) SSharedStateBindingTableState* pBindingTableState = (SSharedStateBindingTableState*)pLinearAddress; ICBE_DPF_STR( output, GFXDBG_HARDWARE, "BINDING_TABLE_STATE\n" ); for( DWORD i = 0; i < numBindingTableEntries; ++i ) { ICBE_DPF_STR( output, GFXDBG_HARDWARE, "\tEntry[ %3d ] : %08x (%x)\n", i, pBindingTableState->DW0.Value, pBindingTableState->DW0.All.SurfaceStatePointer ); pBindingTableState++; } #endif } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_parser_g8.h000066400000000000000000000071361363533017100266650ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once //#include "ContextTypes.h" #include "../inc/common/igfxfmid.h" namespace G6HWC { /*****************************************************************************\ Direct state debug functions \*****************************************************************************/ DWORD DebugCommand( const void* pBuffer, const PLATFORM productID, std::string &output ); DWORD DebugMICommand( const void* pBuffer, const PLATFORM productID, std::string &output ); DWORD DebugGfxCommand( const void* pBuffer, const PLATFORM productID, std::string &output ); /*****************************************************************************\ Indirect state debug functions \*****************************************************************************/ void DebugSamplerStateCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ); void DebugVmeStateCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ); void DebugSamplerIndirectStateCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ); void DebugBindingTableStateCommand( const void* pLinearAddress, const DWORD numBindingTableEntries, const PLATFORM productID, std::string &output ); void DebugSurfaceStateCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ); void DebugMediaSurfaceStateCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ); void DebugInterfaceDescriptorCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ); void DebugInterfaceDescriptorDataCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ); void DebugKernelProgram( const void* pLinearAddress, const DWORD size, std::string &output ); void DebugSurfaceStateBufferLengthCommand( const void* pLinearAddress, const PLATFORM productID, std::string &output ); } // namespace G6HWC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_shared_def_g8.h000066400000000000000000001747551363533017100274710ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_shared_enum_g8.h" // Set packing alignment to a single byte #pragma pack(1) namespace G6HWC { /*****************************************************************************\ STRUCT: SSharedStateBindingTableState (BINDING_TABLE_STATE) \*****************************************************************************/ struct SSharedStateBindingTableState { // DWORD 0 union _DW0 { struct _All { DWORD _Unused : BITFIELD_RANGE( 0,4 ); DWORD SurfaceStatePointer : BITFIELD_RANGE( 5,31 ); // GTT[31:5] S3DStateSurfaceState* } All; DWORD Value; } DW0; }; static_assert(SIZE32(SSharedStateBindingTableState) == 1); /*****************************************************************************\ STRUCT: SGfxSamplerIndirectState (SAMPLER_INDIRECT_STATE) \*****************************************************************************/ struct SGfxSamplerIndirectState { // DWORD 0 float BorderColorRed; // DWORD 1 float BorderColorGreen; // DWORD 2 float BorderColorBlue; // DWORD 3 float BorderColorAlpha; // DWORDs 4-11 should all be set to zero: DWORD _Unused1; DWORD _Unused2; DWORD _Unused3; DWORD _Unused4; DWORD _Unused5; DWORD _Unused6; DWORD _Unused7; DWORD _Unused8; }; static_assert(SIZE32(SGfxSamplerIndirectState) == 12); /*****************************************************************************\ STRUCT: SSharedStateSamplerState ( SAMPLER_STATE ) \*****************************************************************************/ struct SSharedStateSamplerState { // DWORD 0 union _DW0 { struct _All { DWORD ShadowFunction : BITFIELD_RANGE( 0,2 ); // GFXSHAREDSTATE_PREFILTER_OPERATION DWORD TextureLODBias : BITFIELD_RANGE( 3,13 ); // 11-bit signed (S4.6) [-16.0, 16.0) DWORD MinModeFilter : BITFIELD_RANGE( 14,16 ); // GFXSHAREDSTATE_MAPFILTER DWORD MagModeFilter : BITFIELD_RANGE( 17,19 ); // GFXSHAREDSTATE_MAPFILTER DWORD MipModeFilter : BITFIELD_RANGE( 20,21 ); // GFXSHAREDSTATE_MIPFILTER DWORD BaseMipLevel : BITFIELD_RANGE( 22,26 ); // U4.1 [0,13] DWORD _Unused1 : BITFIELD_BIT( 27 ); DWORD LODPreClampEnable : BITFIELD_BIT( 28 ); // bool DWORD TextureBorderColorMode : BITFIELD_BIT( 29 ); // GFXSHAREDSTATE_DEFAULTCOLOR_MODE DWORD _Unused2 : BITFIELD_BIT( 30 ); DWORD SamplerDisable : BITFIELD_BIT( 31 ); // bool } All; struct _Gen7 { DWORD _Unused1 : BITFIELD_BIT( 0 ); // Reserved DWORD TextureLODBias : BITFIELD_RANGE( 1,13 ); // S4.2 2's comp DWORD MinModeFilter : BITFIELD_RANGE( 14,16 ); // GFXSHAREDSTATE_MAPFILTER DWORD MagModeFilter : BITFIELD_RANGE( 17,19 ); // GFXSHAREDSTATE_MAPFILTER DWORD MipModeFilter : BITFIELD_RANGE( 20,21 ); // GFXSHAREDSTATE_MIPFILTER DWORD BaseMipLevel : BITFIELD_RANGE( 22,26 ); // U4.1 [0,13] DWORD _Unused2 : BITFIELD_BIT( 27 ); DWORD LODPreClampEnable : BITFIELD_BIT( 28 ); // bool DWORD TextureBorderColorMode : BITFIELD_BIT( 29 ); // GFXSHAREDSTATE_DEFAULTCOLOR_MODE DWORD _Unused3 : BITFIELD_BIT( 30 ); DWORD SamplerDisable : BITFIELD_BIT( 31 ); // bool } Gen7; struct _Gen9 { DWORD AnisotropicAlgorithm : BITFIELD_BIT( 0 ); // DWORD TextureLODBias : BITFIELD_RANGE( 1,13 ); // S4.2 2's comp DWORD MinModeFilter : BITFIELD_RANGE( 14,16 ); // GFXSHAREDSTATE_MAPFILTER DWORD MagModeFilter : BITFIELD_RANGE( 17,19 ); // GFXSHAREDSTATE_MAPFILTER DWORD MipModeFilter : BITFIELD_RANGE( 20,21 ); // GFXSHAREDSTATE_MIPFILTER DWORD CoarseLODQualityMode : BITFIELD_RANGE( 22,26 ); // U5 DWORD _Unused1 : BITFIELD_BIT( 27 ); DWORD LODPreClampEnable : BITFIELD_BIT( 28 ); // bool DWORD TextureBorderColorMode : BITFIELD_BIT( 29 ); // GFXSHAREDSTATE_DEFAULTCOLOR_MODE DWORD _Unused2 : BITFIELD_BIT( 30 ); DWORD SamplerDisable : BITFIELD_BIT( 31 ); // bool } Gen9; struct _Gen10 { DWORD AnisotropicAlgorithm : BITFIELD_BIT( 0 ); // DWORD TextureLODBias : BITFIELD_RANGE( 1,13 ); // S4.2 2's comp DWORD MinModeFilter : BITFIELD_RANGE( 14,16 ); // GFXSHAREDSTATE_MAPFILTER DWORD MagModeFilter : BITFIELD_RANGE( 17,19 ); // GFXSHAREDSTATE_MAPFILTER DWORD MipModeFilter : BITFIELD_RANGE( 20,21 ); // GFXSHAREDSTATE_MIPFILTER DWORD CoarseLODQualityMode : BITFIELD_RANGE( 22,26 ); // U5 DWORD LODPreClampEnable : BITFIELD_RANGE( 27,28 ); // bool DWORD TextureBorderColorMode : BITFIELD_BIT( 29 ); // GFXSHAREDSTATE_DEFAULTCOLOR_MODE DWORD CpsLODCompensation : BITFIELD_BIT( 30 ); // CPS LOD Compensation Enable DWORD SamplerDisable : BITFIELD_BIT( 31 ); // bool } Gen10; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD TCZAddressControlMode : BITFIELD_RANGE( 0,2 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD TCYAddressControlMode : BITFIELD_RANGE( 3,5 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD TCXAddressControlMode : BITFIELD_RANGE( 6,8 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD CubeSurfaceControlMode : BITFIELD_BIT( 9 ); // GFXSHAREDSTATE_CUBESURFACECONTROLMODE DWORD _Unused : BITFIELD_RANGE( 10,11 ); DWORD MaxLOD : BITFIELD_RANGE( 12,21 ); // U4.6 in LOD units [0.0,13.0] DWORD MinLOD : BITFIELD_RANGE( 22,31 ); // U4.6 in LOD units [0.0,13.0] } All; struct _Gen7 { DWORD CubeSurfaceControlMode : BITFIELD_BIT( 0 ); // GFXSHAREDSTATE_CUBESURFACECONTROLMODE DWORD ShadowFunction : BITFIELD_RANGE( 1,3 ); // GFXSHAREDSTATE_PREFILTER_OPERATION DWORD _Unused : BITFIELD_RANGE( 4,7 ); // Reserved DWORD MaxLOD : BITFIELD_RANGE( 8,19 ); // U4.8 DWORD MinLOD : BITFIELD_RANGE( 20,31 ); // U4.8 } Gen7; struct _Gen8 { DWORD ChromaKeyMode : BITFIELD_BIT( 4 ); // U1 DWORD ChromaKeyIndex : BITFIELD_RANGE( 5,6 ); // U2 DWORD ChromaKeyEnable : BITFIELD_BIT( 7 ); // bool } Gen8; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD _Unused : BITFIELD_RANGE( 0,4 ); DWORD BorderColorPointer : BITFIELD_RANGE( 5,31 ); // DynamicStateOffset[31:5] } All; union _Gen8 { struct _All { DWORD LODClampMagnificationMode : BITFIELD_BIT( 0 ); // U1 DWORD FlexibleFilterVerticalAlignment : BITFIELD_BIT( 1 ); // U1 DWORD FlexibleFilterHorizontalAlignment : BITFIELD_BIT( 2 ); // U1 DWORD FlexibleFilterCoefficientSize : BITFIELD_BIT( 3 ); // U1 DWORD FlexibleFilterMode : BITFIELD_BIT( 4 ); // GFXSHAREDSTATE_FLEXFILTERMODE DWORD _Unused1 : BITFIELD_BIT( 5 ); // Reserved DWORD IndirectStatePointer : BITFIELD_RANGE( 6,23 ); // DynamicStateOffset[23:6] DWORD _Unused2 : BITFIELD_RANGE( 24,31 ); } All; struct _FlexibleFilterSeparable { DWORD _Unused : BITFIELD_RANGE( 0,25 ); DWORD SeparableFilterHeight : BITFIELD_RANGE( 26,27 ); // U2 DWORD SeparableFilterWidth : BITFIELD_RANGE( 28,29 ); // U2 DWORD SeparableFilterCoefficientTableSize : BITFIELD_RANGE( 30,31 ); // U2 } FlexibleFilterSeparable; struct _FlexibleFilterNonSeparable { DWORD _Unused : BITFIELD_RANGE( 0,23 ); DWORD NonSeparableFilterFootprintMask : BITFIELD_RANGE( 24,31 ); // Mask } FlexibleFilterNonSeparable; } Gen8; struct _Gen10 { DWORD LODClampMagnificationMode : BITFIELD_BIT( 0 ); // U1 DWORD _Unused : BITFIELD_RANGE( 1,4 ); DWORD ForceGather4 : BITFIELD_BIT( 5 ); // DWORD IndirectStatePointer : BITFIELD_RANGE( 6,23 ); // DynamicStateOffset[23:6] DWORD _Unused2 : BITFIELD_RANGE( 24,31 ); } Gen10; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD NonNormalizedCoordinatesEnable : BITFIELD_BIT( 1 ); // bool DWORD _Unused1 : BITFIELD_RANGE( 1,12 ); // Reserved DWORD RAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 13 ); // bool DWORD RAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 14 ); // bool DWORD VAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 15 ); // bool DWORD VAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 16 ); // bool DWORD UAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 17 ); // bool DWORD UAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 18 ); // bool DWORD MaximumAnisotropy : BITFIELD_RANGE( 19,21 ); // GFXSHAREDSTATE_ANISORATIO DWORD ChromaKeyMode : BITFIELD_BIT( 22 ); // GFXSHAREDSTATE_CHROMAKEY_MODE DWORD ChromaKeyIndex : BITFIELD_RANGE( 23,24 ); // U2 DWORD ChromaKeyEnable : BITFIELD_BIT( 25 ); // bool DWORD _Unused2 : BITFIELD_RANGE( 26,31 ); // Reserved } All; struct _Gen7 { DWORD TCZAddressControlMode : BITFIELD_RANGE( 0,2 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD TCYAddressControlMode : BITFIELD_RANGE( 3,5 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD TCXAddressControlMode : BITFIELD_RANGE( 6,8 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD _Unused1 : BITFIELD_BIT( 9 ); // Reserved DWORD NonNormalizedCoordinateEnable : BITFIELD_BIT( 10 ); // bool DWORD TrilinearFilterQuality : BITFIELD_RANGE( 11,12 ); // GFXSHAREDSTATE_TRILINEAR_QUALITY DWORD RAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 13 ); // bool DWORD RAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 14 ); // bool DWORD VAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 15 ); // bool DWORD VAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 16 ); // bool DWORD UAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 17 ); // bool DWORD UAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 18 ); // bool DWORD MaximumAnisotropy : BITFIELD_RANGE( 19,21 ); // GFXSHAREDSTATE_ANISORATIO DWORD ChromaKeyMode : BITFIELD_BIT( 22 ); // GFXSHAREDSTATE_CHROMAKEY_MODE DWORD ChromaKeyIndex : BITFIELD_RANGE( 23,24 ); // U2 DWORD ChromaKeyEnable : BITFIELD_BIT( 25 ); // bool DWORD _Unused2 : BITFIELD_RANGE( 26,31 ); // Reserved } Gen7; struct _Gen8 { DWORD _Unused : BITFIELD_RANGE( 22,23 ); // Reserved DWORD NonSeparableFilterFootprintMask : BITFIELD_RANGE( 24,31 ); // Mask } Gen8; struct _Gen9 { DWORD TCZAddressControlMode : BITFIELD_RANGE( 0,2 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD TCYAddressControlMode : BITFIELD_RANGE( 3,5 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD TCXAddressControlMode : BITFIELD_RANGE( 6,8 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD ReductionTypeEnable : BITFIELD_BIT( 9 ); // bool DWORD NonNormalizedCoordinateEnable : BITFIELD_BIT( 10 ); // bool DWORD TrilinearFilterQuality : BITFIELD_RANGE( 11,12 ); // GFXSHAREDSTATE_TRILINEAR_QUALITY DWORD RAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 13 ); // bool DWORD RAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 14 ); // bool DWORD VAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 15 ); // bool DWORD VAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 16 ); // bool DWORD UAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 17 ); // bool DWORD UAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 18 ); // bool DWORD MaximumAnisotropy : BITFIELD_RANGE( 19,21 ); // GFXSHAREDSTATE_ANISORATIO DWORD ReductionType : BITFIELD_RANGE( 22,23 ); // GFXSHAREDSTATE_REDUCTION_TYPE DWORD NonSeparableFilterFootprintMask : BITFIELD_RANGE( 24,31 ); // Mask } Gen9; union _Gen10 { struct _All { DWORD TCZAddressControlMode : BITFIELD_RANGE( 0,2 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD TCYAddressControlMode : BITFIELD_RANGE( 3,5 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD TCXAddressControlMode : BITFIELD_RANGE( 6,8 ); // GFXSHAREDSTATE_TEXCOORDMODE DWORD ReductionTypeEnable : BITFIELD_BIT( 9 ); // bool DWORD NonNormalizedCoordinateEnable : BITFIELD_BIT( 10 ); // bool DWORD TrilinearFilterQuality : BITFIELD_RANGE( 11,12 ); // GFXSHAREDSTATE_TRILINEAR_QUALITY DWORD RAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 13 ); // bool DWORD RAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 14 ); // bool DWORD VAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 15 ); // bool DWORD VAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 16 ); // bool DWORD UAddressMinFilterAddressRoundingEnable : BITFIELD_BIT( 17 ); // bool DWORD UAddressMagFilterAddressRoundingEnable : BITFIELD_BIT( 18 ); // bool DWORD MaximumAnisotropy : BITFIELD_RANGE( 19,21 ); // GFXSHAREDSTATE_ANISORATIO DWORD ReductionType : BITFIELD_RANGE( 22,23 ); // GFXSHAREDSTATE_REDUCTION_TYPE DWORD NonSeparableFilterFootprintMask : BITFIELD_RANGE( 24,31 ); // Mask } ALL; struct _FlexibleFilterMinMagMode { DWORD FlexibleFilterDisableClamping : BITFIELD_BIT( 10 ); // }FlexibleFilterMinMagMode; } Gen10; DWORD Value; } DW3; }; static_assert(SIZE32(SSharedStateSamplerState) == 4); /*****************************************************************************\ STRUCT: SSharedStateSearchPathLUTState \*****************************************************************************/ struct SSharedStateSearchPathLUTState { // DWORD 0 union _DW0 { struct _Bitfield { DWORD SearchPathLocation_X_0 : 4; DWORD SearchPathLocation_Y_0 : 4; DWORD SearchPathLocation_X_1 : 4; DWORD SearchPathLocation_Y_1 : 4; DWORD SearchPathLocation_X_2 : 4; DWORD SearchPathLocation_Y_2 : 4; DWORD SearchPathLocation_X_3 : 4; DWORD SearchPathLocation_Y_3 : 4; } BitField; struct _Byte { BYTE Byte0; BYTE Byte1; BYTE Byte2; BYTE Byte3; } Byte; DWORD Value; } DW0; }; static_assert(SIZE32(SSharedStateSearchPathLUTState) == 1); /*****************************************************************************\ STRUCT: SSharedStateRDLUTSet \*****************************************************************************/ struct SSharedStateRDLUTSet { // DWORD 0 union _DW0 { struct _Bitfield { DWORD LUT_MbMode_0 : 8; DWORD LUT_MbMode_1 : 8; DWORD LUT_MbMode_2 : 8; DWORD LUT_MbMode_3 : 8; } BitField; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _Bitfield { DWORD LUT_MbMode_4 : 8; DWORD LUT_MbMode_5 : 8; DWORD LUT_MbMode_6 : 8; DWORD LUT_MbMode_7 : 8; } BitField; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _Bitfield { DWORD LUT_MV_0 : 8; DWORD LUT_MV_1 : 8; DWORD LUT_MV_2 : 8; DWORD LUT_MV_3 : 8; } BitField; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _Bitfield { DWORD LUT_MV_4 : 8; DWORD LUT_MV_5 : 8; DWORD LUT_MV_6 : 8; DWORD LUT_MV_7 : 8; } BitField; DWORD Value; } DW3; }; static_assert(SIZE32(SSharedStateRDLUTSet) == 4); /*****************************************************************************\ STRUCT: SSharedStateVmeState ( VME_STATE ) \*****************************************************************************/ struct SSharedStateVmeState { // DWORD 0 - DWORD 13 SSharedStateSearchPathLUTState SearchPath[ g_cNumSearchPathStatesGen6 ]; // DWORD 14 union _DW14 { struct _Bitfield { DWORD LUT_MbMode_8_0 : 8; DWORD LUT_MbMode_9_0 : 8; DWORD LUT_MbMode_8_1 : 8; DWORD LUT_MbMode_9_1 : 8; } BitField; DWORD Value; } DW14; // DWORD 15 union _DW15 { struct _Bitfield { DWORD LUT_MbMode_8_2 : 8; DWORD LUT_MbMode_9_2 : 8; DWORD LUT_MbMode_8_3 : 8; DWORD LUT_MbMode_9_3 : 8; } BitField; DWORD Value; } DW15; // DWORD 16 - DWORD 31 struct SSharedStateRDLUTSet RdLutSet[ g_cNumMBModeSetsGen6 ]; }; static_assert(SIZE32(SSharedStateVmeState) == 32); /*****************************************************************************\ STRUCT: SSamplerStateErodeDilateMinMaxFilter ( SAMPLER_STATE Erode/Dilate/MinMaxFilter ) \*****************************************************************************/ struct SSamplerStateErodeDilateMinMaxFilter { DWORD DW0; DWORD DW1; DWORD DW2; DWORD DW3; DWORD DW4; DWORD DW5; DWORD DW6; DWORD DW7; }; static_assert(SIZE32(SSamplerStateErodeDilateMinMaxFilter) == 8); /*****************************************************************************\ STRUCT: SSharedStateSurfaceState ( SURFACE_STATE ) \*****************************************************************************/ struct SSharedStateSurfaceState { // DWORD 0 union _DW0 { struct _All { DWORD CubeFaceEnablesPositiveZ : BITFIELD_BIT( 0 ); // bool DWORD CubeFaceEnablesNegativeZ : BITFIELD_BIT( 1 ); // bool DWORD CubeFaceEnablesPositiveY : BITFIELD_BIT( 2 ); // bool DWORD CubeFaceEnablesNegativeY : BITFIELD_BIT( 3 ); // bool DWORD CubeFaceEnablesPositiveX : BITFIELD_BIT( 4 ); // bool DWORD CubeFaceEnablesNegativeX : BITFIELD_BIT( 5 ); // bool DWORD MediaBoundaryPixelMode : BITFIELD_RANGE( 6,7 ); // GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_MODE DWORD RenderCacheReadWriteMode : BITFIELD_BIT( 8 ); // GFXSHAREDSTATE_RENDER_CACHE_READ_WRITE_MODE DWORD CubeMapCornerMode : BITFIELD_BIT( 9 ); // GFXSHAREDSTATE_CUBECORNERMODE DWORD MipMapLayoutMode : BITFIELD_BIT( 10 ); // GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT DWORD VerticalLineStrideOffset : BITFIELD_BIT( 11 ); // U1 DWORD VerticalLineStride : BITFIELD_BIT( 12 ); // U1 DWORD _Unused1 : BITFIELD_RANGE( 13,17 ); DWORD SurfaceFormat : BITFIELD_RANGE( 18,26 ); // GFXSHAREDSTATE_SURFACEFORMAT DWORD DataReturnFormat : BITFIELD_BIT( 27 ); // GFXSHAREDSTATE_SURFACERETURNFORMAT DWORD _Unused2 : BITFIELD_BIT( 28 ); DWORD SurfaceType : BITFIELD_RANGE( 29,31 ); // GFXSHAREDSTATE_SURFACETYPE } All; struct _Gen7 { DWORD CubeFaceEnablesPositiveZ : BITFIELD_BIT( 0 ); // bool DWORD CubeFaceEnablesNegativeZ : BITFIELD_BIT( 1 ); // bool DWORD CubeFaceEnablesPositiveY : BITFIELD_BIT( 2 ); // bool DWORD CubeFaceEnablesNegativeY : BITFIELD_BIT( 3 ); // bool DWORD CubeFaceEnablesPositiveX : BITFIELD_BIT( 4 ); // bool DWORD CubeFaceEnablesNegativeX : BITFIELD_BIT( 5 ); // bool DWORD MediaBoundaryPixelMode : BITFIELD_RANGE( 6,7 ); // GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_MODE DWORD RenderCacheReadWriteMode : BITFIELD_BIT( 8 ); // GFXSHAREDSTATE_RENDER_CACHE_READ_WRITE_MODE DWORD _Unused1 : BITFIELD_BIT( 9 ); // Reserved DWORD SurfaceArraySpacing : BITFIELD_BIT( 10 ); // GFXSHAREDSTATE_SURFACE_ARRAY_SPACING DWORD VerticalLineStrideOffset : BITFIELD_BIT( 11 ); // U1 DWORD VerticalLineStride : BITFIELD_BIT( 12 ); // U1 DWORD TileWalk : BITFIELD_BIT( 13 ); // GFXSHAREDSTATE_TILEWALK DWORD TiledSurface : BITFIELD_BIT( 14 ); // bool DWORD _Unused2 : BITFIELD_RANGE( 15,17 ); DWORD SurfaceFormat : BITFIELD_RANGE( 18,26 ); // GFXSHAREDSTATE_SURFACEFORMAT DWORD _Unused3 : BITFIELD_BIT( 27 ); DWORD SurfaceArray : BITFIELD_BIT( 28 ); // bool DWORD SurfaceType : BITFIELD_RANGE( 29,31 ); // GFXSHAREDSTATE_SURFACETYPE } Gen7; struct _Gen7_Media { DWORD SurfaceBaseAddress; // GTT[31:0] } Gen7Media; struct _Gen8 { DWORD CubeFaceEnablesPositiveZ : BITFIELD_BIT( 0 ); // bool DWORD CubeFaceEnablesNegativeZ : BITFIELD_BIT( 1 ); // bool DWORD CubeFaceEnablesPositiveY : BITFIELD_BIT( 2 ); // bool DWORD CubeFaceEnablesNegativeY : BITFIELD_BIT( 3 ); // bool DWORD CubeFaceEnablesPositiveX : BITFIELD_BIT( 4 ); // bool DWORD CubeFaceEnablesNegativeX : BITFIELD_BIT( 5 ); // bool DWORD MediaBoundaryPixelMode : BITFIELD_RANGE( 6,7 ); // GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_MODE DWORD RenderCacheReadWriteMode : BITFIELD_BIT( 8 ); // GFXSHAREDSTATE_RENDER_CACHE_READ_WRITE_MODE DWORD SurfaceArraySpacing : BITFIELD_BIT( 9 ); // U1 DWORD VerticalLineStrideOffset : BITFIELD_BIT( 10 ); // U1 DWORD VerticalLineStride : BITFIELD_BIT( 11 ); // U1 DWORD TileMode : BITFIELD_RANGE( 12,13 ); // GFXSHAREDSTATE_TILEMODE DWORD SurfaceHorizontalAlignment : BITFIELD_RANGE( 14,15 ); // U2 DWORD SurfaceVerticalAlignment : BITFIELD_RANGE( 16,17 ); // U2 DWORD SurfaceFormat : BITFIELD_RANGE( 18,26 ); // GFXSHAREDSTATE_SURFACEFORMAT DWORD _Unused : BITFIELD_BIT( 27 ); // Reserved DWORD SurfaceArray : BITFIELD_BIT( 28 ); // bool DWORD SurfaceType : BITFIELD_RANGE( 29,31 ); // GFXSHAREDSTATE_SURFACETYPE } Gen8; struct _Gen8_Media { DWORD Reserved : BITFIELD_RANGE( 0, 31 ); } Gen8Media; struct _Gen9 { DWORD CubeFaceEnablesPositiveZ : BITFIELD_BIT( 0 ); // bool DWORD CubeFaceEnablesNegativeZ : BITFIELD_BIT( 1 ); // bool DWORD CubeFaceEnablesPositiveY : BITFIELD_BIT( 2 ); // bool DWORD CubeFaceEnablesNegativeY : BITFIELD_BIT( 3 ); // bool DWORD CubeFaceEnablesPositiveX : BITFIELD_BIT( 4 ); // bool DWORD CubeFaceEnablesNegativeX : BITFIELD_BIT( 5 ); // bool DWORD MediaBoundaryPixelMode : BITFIELD_RANGE( 6,7 ); // GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_MODE DWORD RenderCacheReadWriteMode : BITFIELD_BIT( 8 ); // GFXSHAREDSTATE_RENDER_CACHE_READ_WRITE_MODE DWORD SurfaceArraySpacing : BITFIELD_BIT( 9 ); // U1 DWORD VerticalLineStrideOffset : BITFIELD_BIT( 10 ); // U1 DWORD VerticalLineStride : BITFIELD_BIT( 11 ); // U1 DWORD TileMode : BITFIELD_RANGE( 12,13 ); // GFXSHAREDSTATE_TILEMODE DWORD SurfaceHorizontalAlignment : BITFIELD_RANGE( 14,15 ); // U2 DWORD SurfaceVerticalAlignment : BITFIELD_RANGE( 16,17 ); // U2 DWORD SurfaceFormat : BITFIELD_RANGE( 18,26 ); // GFXSHAREDSTATE_SURFACEFORMAT DWORD ASTCEnable : BITFIELD_BIT( 27 ); // bool DWORD SurfaceArray : BITFIELD_BIT( 28 ); // bool DWORD SurfaceType : BITFIELD_RANGE( 29,31 ); // GFXSHAREDSTATE_SURFACETYPE } Gen9; DWORD Value; } DW0; // DWORD 1 union _DW1 { struct _All { DWORD SurfaceBaseAddress; } All; struct _Gen7_Media { DWORD UVPixelOffsetVDirection : BITFIELD_RANGE( 0, 1 ); // U0.2 DWORD PictureStructure : BITFIELD_RANGE( 2, 3 ); // ? DWORD Width : BITFIELD_RANGE( 4,17 ); // U14 DWORD Height : BITFIELD_RANGE( 18,31 ); // U14 } Gen7Media; struct _Gen8 { DWORD SurfaceQPitch : BITFIELD_RANGE( 0,14 ); // QPitch[16:2] DWORD _Unused1 : BITFIELD_RANGE( 15,23 ); // Reserved DWORD SurfaceObjectAgeControl : BITFIELD_RANGE( 24,25 ); // GFXSTATE_SOURCE_AGE_CONTROL DWORD SurfaceObjectEncryptedDataEnable : BITFIELD_BIT( 26 ); // bool DWORD SurfaceObjectTargetCache : BITFIELD_RANGE( 27,28 ); // GFXSTATE_TARGET_CACHE DWORD SurfaceObjectCacheabilityControl : BITFIELD_RANGE( 29,30 ); // GFXSTATE_CACHEABILITY_CONTROL DWORD _Unused2 : BITFIELD_BIT( 31 ); // Reserved } Gen8; struct _Gen9 { DWORD SurfaceQPitch : BITFIELD_RANGE( 0,14 ); // QPitch[16:2] DWORD _Unused1 : BITFIELD_RANGE( 15,18 ); // Reserved DWORD BaseMipLevel : BITFIELD_RANGE( 19,23 ); // DWORD EncryptedDataEnable : BITFIELD_BIT( 24 ); // Reserved DWORD MOCSTablesIndex : BITFIELD_RANGE( 25,30 ); // define the L3 and system cache memory properties DWORD _Unused2 : BITFIELD_BIT( 31 ); // Reserved } Gen9; struct _Gen10 { DWORD SurfaceQPitch : BITFIELD_RANGE( 0,14 ); // QPitch[16:2] DWORD _Unused1 : BITFIELD_RANGE( 15,18 ); // Reserved DWORD BaseMipLevel : BITFIELD_RANGE( 19,23 ); // DWORD EncryptedDataEnable : BITFIELD_BIT( 24 ); // Reserved DWORD MOCSTablesIndex : BITFIELD_RANGE( 25,30 ); // define the L3 and system cache memory properties DWORD _Unused2 : BITFIELD_BIT( 31 ); // Reserved } Gen10; struct _Gen10_Media { DWORD UVPixelOffsetVDirection : BITFIELD_RANGE( 0, 1 ); // U0.2 DWORD PictureStructure : BITFIELD_RANGE( 2, 3 ); // ? DWORD Width : BITFIELD_RANGE( 4,17 ); // U14 //width except if format is structure buffer :reading the Data base Structure buffer (or) Test Vector Structure Buffer (or) Index Table. DWORD Height : BITFIELD_RANGE( 18,31 ); // U14 //height except if format is structure buffer :reading the Data base Structure buffer (or) Test Vector Structure Buffer (or) Index Table. } Gen10Media; DWORD Value; } DW1; // DWORD 2 union _DW2 { struct _All { DWORD RenderTargetRotation : BITFIELD_RANGE( 0,1 ); // GFXSHAREDSTATE_RENDER_TARGET_ROTATION DWORD MipCount : BITFIELD_RANGE( 2,5 ); // U4 in LOD units DWORD Width : BITFIELD_RANGE( 6,18 ); // U13 DWORD Height : BITFIELD_RANGE( 19,31 ); // U13 } All; struct _Gen7 { DWORD Width : BITFIELD_RANGE( 0,13 ); // U14 DWORD _Unused1 : BITFIELD_RANGE( 14,15 ); // U2 DWORD Height : BITFIELD_RANGE( 16,29 ); // U14 DWORD _Unused2 : BITFIELD_RANGE( 30,31 ); } Gen7; struct _Gen7_Media { DWORD TiledSurface : BITFIELD_BIT( 0 ); // bool DWORD TileWalk : BITFIELD_BIT( 1 ); // GFX3DSTATE_TILEWALK DWORD HalfPitchForChroma : BITFIELD_BIT( 2 ); // bool DWORD SurfacePitch : BITFIELD_RANGE( 3,20 ); // U18 DWORD _Unused1 : BITFIELD_BIT( 21 ); DWORD SurfaceObjectControlState : BITFIELD_RANGE( 22,25 ); // ? DWORD _Unused2 : BITFIELD_BIT( 26 ); DWORD InterleaveChroma : BITFIELD_BIT( 27 ); // bool DWORD SurfaceFormat : BITFIELD_RANGE( 28,31 ); // MEDIASTATE_SURFACEFORMAT } Gen7Media; struct _Gen8_Media { DWORD TiledSurface : BITFIELD_BIT( 0 ); // bool DWORD TileWalk : BITFIELD_BIT( 1 ); // GFX3DSTATE_TILEWALK DWORD HalfPitchForChroma : BITFIELD_BIT( 2 ); // bool DWORD SurfacePitch : BITFIELD_RANGE( 3,20 ); // U18 DWORD AddressControl : BITFIELD_BIT( 21 ); // ? DWORD _Unused : BITFIELD_RANGE( 22,25 ); DWORD InterleaveChroma : BITFIELD_BIT( 26 ); // bool DWORD SurfaceFormat : BITFIELD_RANGE( 27,31 ); // MEDIASTATE_SURFACEFORMAT } Gen8Media; struct _Gen9_Media { DWORD TiledSurface : BITFIELD_BIT( 0 ); // bool DWORD TileWalk : BITFIELD_BIT( 1 ); // GFX3DSTATE_TILEWALK DWORD HalfPitchForChroma : BITFIELD_BIT( 2 ); // bool DWORD SurfacePitch : BITFIELD_RANGE( 3,20 ); // U18 DWORD AddressControl : BITFIELD_BIT( 21 ); // ? DWORD MemoryCompressionEnable : BITFIELD_BIT( 22 ); // ? DWORD MemoryCompressionMode : BITFIELD_BIT( 23 ); // ? DWORD OffsetVDirection : BITFIELD_BIT( 24 ); // Cr(V)/Cb(U) Pixel Offset V Direction MSB DWORD OffsetUDirection : BITFIELD_BIT( 25 ); // Cr(V)/Cb(U) Pixel Offset U Direction DWORD InterleaveChroma : BITFIELD_BIT( 26 ); // bool DWORD SurfaceFormat : BITFIELD_RANGE( 27,31 ); // MEDIASTATE_SURFACEFORMAT } Gen9Media; DWORD Value; } DW2; // DWORD 3 union _DW3 { struct _All { DWORD TileWalk : BITFIELD_BIT( 0 ); // GFXSHAREDSTATE_TILEWALK DWORD TiledSurface : BITFIELD_BIT( 1 ); // bool DWORD _Unused1 : BITFIELD_BIT( 2 ); DWORD SurfacePitch : BITFIELD_RANGE( 3,19 ); // U17 DWORD _Unused2 : BITFIELD_BIT( 20 ); DWORD Depth : BITFIELD_RANGE( 21,31 ); // U11 } All; struct _Gen7 { DWORD SurfacePitch : BITFIELD_RANGE( 0,17 ); // U17 DWORD _Unused1 : BITFIELD_RANGE( 18,20 ); // Reserved DWORD Depth : BITFIELD_RANGE( 21,31 ); // U11 } Gen7; struct _Gen7_Media { DWORD YOffsetForU : BITFIELD_RANGE( 0,13 ); // U14 DWORD _Unused1 : BITFIELD_RANGE( 14,15 ); DWORD XOffsetForU : BITFIELD_RANGE( 16,29 ); // U14 DWORD _Unused2 : BITFIELD_RANGE( 30,31 ); } Gen7Media; struct _Gen10 { DWORD SurfacePitch : BITFIELD_RANGE( 0,17 ); // U17 DWORD _Unused1 : BITFIELD_RANGE( 18,19 ); // Reserved DWORD TileAddressMappingMode : BITFIELD_BIT( 20 ); // 0: Gen9, 1: Gen10 DWORD Depth : BITFIELD_RANGE( 21,31 ); // U11 } Gen10; DWORD Value; } DW3; // DWORD 4 union _DW4 { struct _All { DWORD MultisamplePositionPaletteIndex : BITFIELD_RANGE( 0,2 ); // U3 DWORD _Unused1 : BITFIELD_BIT( 3 ); DWORD NumMultisamples : BITFIELD_RANGE( 4,6 ); // GFXSHAREDSTATE_NUM_MULTISAMPLES DWORD _Unused2 : BITFIELD_BIT( 7 ); DWORD RenderTargetViewExtent : BITFIELD_RANGE( 8,16 ); // U9 DWORD MinimumArrayElement : BITFIELD_RANGE( 17,27 ); // U9 DWORD SurfaceMinLOD : BITFIELD_RANGE( 28,31 ); // U4 in LOD units } All; union _Gen7 { struct _SurfaceAll { DWORD MultisamplePositionPaletteIndex : BITFIELD_RANGE( 0,2 ); // U3 DWORD NumMultisamples : BITFIELD_RANGE( 3,5 ); // GFXSHAREDSTATE_NUM_MULTISAMPLES DWORD MultisampledSurfaceStorageFormat : BITFIELD_BIT( 6 ); // GFXSHAREDSTATE_MSFMT DWORD RenderTargetViewExtent : BITFIELD_RANGE( 7,17 ); // U11 DWORD MinimumArrayElement : BITFIELD_RANGE( 18,28 ); // U11 DWORD RenderTargetRotation : BITFIELD_RANGE( 29,30 ); // U4 in LOD units DWORD _Unused : BITFIELD_BIT( 31 ); // Reserved } SurfaceAll; struct _SurfaceStrBuf { DWORD MinimumArrayElement : BITFIELD_RANGE( 0,26 ); // U27 DWORD _Unused : BITFIELD_RANGE( 27,31 ); // Reserved } SurfaceStrBuf; } Gen7; struct _Gen7_Media { DWORD YOffsetforV : BITFIELD_RANGE( 0,14 ); // U15 DWORD _Unused1 : BITFIELD_BIT( 15 ); DWORD XOffsetforV : BITFIELD_RANGE( 16,29 ); // U14 DWORD _Unused2 : BITFIELD_RANGE( 30,31 ); } Gen7Media; union _Gen10 { struct _SurfaceAll { DWORD MultisamplePositionPaletteIndex : BITFIELD_RANGE( 0,2 ); // U3 DWORD NumMultisamples : BITFIELD_RANGE( 3,5 ); // GFXSHAREDSTATE_NUM_MULTISAMPLES DWORD MultisampledSurfaceStorageFormat : BITFIELD_BIT( 6 ); // GFXSHAREDSTATE_MSFMT DWORD RenderTargetViewExtent : BITFIELD_RANGE( 7,17 ); // U11 DWORD MinimumArrayElement : BITFIELD_RANGE( 18,28 ); // U11 DWORD RenderTargetRotation : BITFIELD_RANGE( 29,30 ); // U4 in LOD units DWORD ForceNonComparisonReductionType : BITFIELD_BIT( 31 ); } SurfaceAll; struct _SurfaceStrBuf { DWORD _Unused : BITFIELD_RANGE( 0,31 ); // Reserved } SurfaceStrBuf; } Gen10; DWORD Value; } DW4; // DWORD 5 union _DW5 { struct _All { DWORD _Unused : BITFIELD_RANGE( 0,15 ); DWORD SurfaceCacheabilityControl : BITFIELD_RANGE( 16,17 ); // GFXSHAREDSTATE_CACHEABILITY_CONTROL DWORD SurfaceGraphicsDataType : BITFIELD_BIT( 18 ); // GFXSHAREDSTATE_GRAPHICS_DATATYPE_SOURCE DWORD SurfaceEncryptedDataEnable : BITFIELD_BIT( 19 ); // bool DWORD YOffset : BITFIELD_RANGE( 20,23 ); // U9 DWORD SurfaceVerticalAlignment : BITFIELD_BIT( 24 ); // GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT DWORD XOffset : BITFIELD_RANGE( 25,31 ); // U4 in LOD units } All; struct _Gen7 { DWORD MipCountLOD : BITFIELD_RANGE( 0,3 ); // U4 DWORD SurfaceMinLOD : BITFIELD_RANGE( 4,7 ); // U4 // bit 14 - Coherency Type (Gen7.5+) // bit 15 - Stateless Data PortAccess Force Write Thru (Gen7.5+) DWORD _Unused1 : BITFIELD_RANGE( 8,15 ); // Reserved DWORD CacheabilityControlL3 : BITFIELD_BIT( 16 ); // GFXSHAREDSTATE_L3_CACHEABILITY_CONTROL DWORD CacheabilityControlLLC : BITFIELD_BIT( 17 ); // GFXSHAREDSTATE_L3_CACHEABILITY_CONTROL DWORD SurfaceGraphicsDataType : BITFIELD_BIT( 18 ); // GFXSHAREDSTATE_GRAPHICS_DATATYPE_SOURCE DWORD SurfaceEncryptedDataEnable : BITFIELD_BIT( 19 ); // bool DWORD YOffset : BITFIELD_RANGE( 20,23 ); // U9 DWORD _Unused2 : BITFIELD_BIT( 24 ); // Reserved DWORD XOffset : BITFIELD_RANGE( 25,31 ); // U4 in LOD units } Gen7; struct _Gen7_Media { DWORD _Unused : BITFIELD_RANGE( 0,29 ); DWORD VerticalLineStrideOffest : BITFIELD_BIT( 30 ); // U1, Gen7.5+ DWORD VerticalLineStride : BITFIELD_BIT( 31 ); // U1, Gen7.5+ } Gen7Media; struct _Gen8 { DWORD MipCountLOD : BITFIELD_RANGE( 0,3 ); // U4 DWORD SurfaceMinLOD : BITFIELD_RANGE( 4,7 ); // U4 // bit 14 - Coherency Type (Gen8+) DWORD _Unused1 : BITFIELD_RANGE( 8,20 ); // Reserved DWORD YOffset : BITFIELD_RANGE( 21,23 ); // U8 DWORD _Unused2 : BITFIELD_BIT( 24 ); // Reserved DWORD XOffset : BITFIELD_RANGE( 25,31 ); // U4 in LOD units } Gen8; struct _Gen8_Media { DWORD SurfaceObjectControlState : BITFIELD_RANGE( 0, 6 ); // MEMORY_OBJECT_CONTROL_STATE DWORD _Unused : BITFIELD_RANGE( 7,29 ); DWORD VerticalLineStrideOffset : BITFIELD_BIT( 30 ); DWORD VerticalLineStride : BITFIELD_BIT( 31 ); } Gen8Media; struct _Gen9 { DWORD MipCountLOD : BITFIELD_RANGE( 0,3 ); // U4 DWORD SurfaceMinLOD : BITFIELD_RANGE( 4,7 ); // U4 DWORD MipTailStartLOD : BITFIELD_RANGE( 8, 11 ); // MipTailStartLOD DWORD _Unused1 : BITFIELD_RANGE( 12, 13 ); // reserved DWORD CoherencyType : BITFIELD_BIT( 14 ); // Coherency Type (Gen8+) DWORD TiledResourceVerticalAlignment : BITFIELD_RANGE( 15, 16 ); // DWORD TiledResourceHorizontalAlignment : BITFIELD_RANGE( 17, 18 ); // DWORD TiledResourceEnable : BITFIELD_BIT( 19 ); // bool DWORD _Unused2 : BITFIELD_BIT( 20 ); // Reserved DWORD YOffset : BITFIELD_RANGE( 21,23 ); // U8 DWORD _Unused3 : BITFIELD_BIT( 24 ); // Reserved DWORD XOffset : BITFIELD_RANGE( 25,31 ); // U4 in LOD units } Gen9; struct _Gen9_Media { DWORD SurfaceObjectControlState : BITFIELD_RANGE( 0, 6 ); // MEMORY_OBJECT_CONTROL_STATE DWORD _Unused : BITFIELD_RANGE( 7,17 ); DWORD TiledResourceMode : BITFIELD_RANGE( 18,19 ); DWORD _Unused2 : BITFIELD_RANGE( 20,29 ); // Reserved DWORD VerticalLineStrideOffset : BITFIELD_BIT( 30 ); DWORD VerticalLineStride : BITFIELD_BIT( 31 ); } Gen9Media; struct _Gen10_Media { DWORD SurfaceObjectControlState : BITFIELD_RANGE( 0, 6 ); // MEMORY_OBJECT_CONTROL_STATE DWORD _Unused : BITFIELD_RANGE( 7,17 ); DWORD TiledResourceMode : BITFIELD_RANGE( 18,19 ); DWORD Depth : BITFIELD_RANGE( 20,23 ); DWORD _Unused2 : BITFIELD_RANGE( 24,29 ); // Reserved DWORD VerticalLineStrideOffset : BITFIELD_BIT( 30 ); DWORD VerticalLineStride : BITFIELD_BIT( 31 ); } Gen10Media; DWORD Value; } DW5; // DWORD 6 union _DW6 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; union _Gen7 { struct _SurfaceMCS { DWORD MCSEnable : BITFIELD_BIT( 0 ); // bool DWORD _Unused : BITFIELD_RANGE( 1,2 ); // Reserved DWORD MCSSurfacePitch : BITFIELD_RANGE( 3,11 ); // U9 DWORD MCSBaseAddress : BITFIELD_RANGE( 12,31 ); // GraphicsAddress[31:12] } SurfaceMCS; struct _SurfaceAppendCounter { DWORD AppendCounterEnable : BITFIELD_BIT( 0 ); // bool DWORD _Unused : BITFIELD_RANGE( 2,5 ); DWORD AppendCounterAddress : BITFIELD_RANGE( 6,31 ); // GraphicsAddress[31:12] } SurfaceAppendCounter; } Gen7; struct _Gen8_Media { DWORD SurfaceBaseAddress : BITFIELD_RANGE( 0, 31 ); } Gen8Media; union _Gen9 { struct _SurfacePlanar { DWORD YOffset : BITFIELD_RANGE( 0, 13 ); // U14 DWORD _Unused1 : BITFIELD_RANGE( 14, 15 ); // reserved DWORD XOffset : BITFIELD_RANGE( 16, 29 ); // U14 DWORD _Unused2 : BITFIELD_RANGE( 30, 31 ); // reserved } SurfacePlanar; struct _SurfaceOther { DWORD AuxiliarySurfaceMode : BITFIELD_RANGE( 0, 1 ); // DWORD RenderTargetCompressionEnable : BITFIELD_BIT( 2 ); // DWORD AuxiliarySurfacePitch : BITFIELD_RANGE( 3, 11 ); // U9 DWORD _Unused1 : BITFIELD_RANGE( 12, 15 ); // reserved DWORD AuxilarySurfaceQPitch : BITFIELD_RANGE( 16, 30 ); // DWORD _Unused2 : BITFIELD_BIT( 31 ); // reserved } SurfaceOther; } Gen9; DWORD Value; } DW6; // DWORD 7 union _DW7 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen7 { DWORD ResourceMinLOD : BITFIELD_RANGE( 0,11 ); // 4.8 DWORD _Unused : BITFIELD_RANGE( 12,27 ); // Reserved DWORD ClearColorAlpha : BITFIELD_BIT( 28 ); // GFXSHAREDSTATE_CLEARCOLOR DWORD ClearColorBlue : BITFIELD_BIT( 29 ); // GFXSHAREDSTATE_CLEARCOLOR DWORD ClearColorGreen : BITFIELD_BIT( 30 ); // GFXSHAREDSTATE_CLEARCOLOR DWORD ClearColorRed : BITFIELD_BIT( 31 ); // GFXSHAREDSTATE_CLEARCOLOR } Gen7; struct _Gen7_5 { DWORD ResourceMinLOD : BITFIELD_RANGE( 0,11 ); // 4.8 DWORD _Unused : BITFIELD_RANGE( 12,15 ); DWORD ShaderChannelSelectAlpha : BITFIELD_RANGE( 16,18 ); // GFXSHAREDSTATE_SHADERCHANNELSELECT DWORD ShaderChannelSelectBlue : BITFIELD_RANGE( 19,21 ); // GFXSHAREDSTATE_SHADERCHANNELSELECT DWORD ShaderChannelSelectGreen : BITFIELD_RANGE( 22,24 ); // GFXSHAREDSTATE_SHADERCHANNELSELECT DWORD ShaderChannelSelectRed : BITFIELD_RANGE( 25,27 ); // GFXSHAREDSTATE_SHADERCHANNELSELECT DWORD ClearColorAlpha : BITFIELD_BIT( 28 ); // GFXSHAREDSTATE_CLEARCOLOR DWORD ClearColorBlue : BITFIELD_BIT( 29 ); // GFXSHAREDSTATE_CLEARCOLOR DWORD ClearColorGreen : BITFIELD_BIT( 30 ); // GFXSHAREDSTATE_CLEARCOLOR DWORD ClearColorRed : BITFIELD_BIT( 31 ); // GFXSHAREDSTATE_CLEARCOLOR } Gen7_5; struct _Gen8_Media { DWORD _Unused : BITFIELD_RANGE( 16, 31 ); DWORD SurfaceBaseAddressHigh : BITFIELD_RANGE( 0, 15 ); } Gen8Media; struct _Gen9 { DWORD ResourceMinLOD : BITFIELD_RANGE( 0,11 ); // 4.8 DWORD _Unused1 : BITFIELD_RANGE( 12,15 ); DWORD ShaderChannelSelectAlpha : BITFIELD_RANGE( 16,18 ); // GFXSHAREDSTATE_SHADERCHANNELSELECT DWORD ShaderChannelSelectBlue : BITFIELD_RANGE( 19,21 ); // GFXSHAREDSTATE_SHADERCHANNELSELECT DWORD ShaderChannelSelectGreen : BITFIELD_RANGE( 22,24 ); // GFXSHAREDSTATE_SHADERCHANNELSELECT DWORD ShaderChannelSelectRed : BITFIELD_RANGE( 25,27 ); // GFXSHAREDSTATE_SHADERCHANNELSELECT DWORD _Unused2 : BITFIELD_RANGE( 28,31 ); // reserved } Gen9; DWORD Value; } DW7; union _DW8 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen8 { DWORD SurfaceBaseAddress : BITFIELD_RANGE( 0,31 ); // GTT[31:0] } Gen8; DWORD Value; } DW8; union _DW9 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen8 { DWORD Surface64bitBaseAddress : BITFIELD_RANGE( 0,15 ); // GTT[47:32] DWORD _Unused : BITFIELD_RANGE( 16,31 ); // Reserved } Gen8; DWORD Value; } DW9; union _DW10 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen8 { DWORD AuxiliarySurfaceBaseAddress : BITFIELD_RANGE( 0,31 ); // GTT[31:0] } Gen8; union _Gen9 { struct _SurfacePlanar { DWORD QuiltWidth : BITFIELD_RANGE( 0, 4 ); // SKL U5 DWORD QuiltHeight : BITFIELD_RANGE( 5, 9 ); // SKL U5 DWORD _Unused : BITFIELD_RANGE( 10, 31 ); } SurfacePlanar; struct _SurfaceOther { DWORD QuiltWidth : BITFIELD_RANGE( 0, 4 ); // SKL U5 DWORD QuiltHeight : BITFIELD_RANGE( 5, 9 ); // SKL U5 DWORD _Unused : BITFIELD_RANGE( 10, 11 ); DWORD AuxiliarySurfaceBaseAddress : BITFIELD_RANGE( 12, 31 ); // GTT[31:0] } SurfaceOther; } Gen9; DWORD Value; } DW10; union _DW11 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen8 { DWORD Auxiliary64bitBaseAddress : BITFIELD_RANGE( 0,15 ); // GTT[47:32] DWORD _Unused : BITFIELD_RANGE( 16,31 ); // Reserved } Gen8; union _Gen9 { struct _SurfacePlanar { DWORD YOffsetVplane : BITFIELD_RANGE( 0, 13); DWORD _Unused : BITFIELD_RANGE( 14,15); // reserved DWORD XOffsetVplane : BITFIELD_RANGE( 16,29); DWORD _Unused2 : BITFIELD_RANGE( 30,31); // reserved } SurfacePlanar; struct _SurfaceOther { DWORD AuxiliarySurfaceBaseAddress : BITFIELD_RANGE( 0, 31 ); // GTT[32:63] } SurfaceOther; } Gen9; DWORD Value; } DW11; union _DW12 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen8 { DWORD HierarchicalDepthClearValue : BITFIELD_RANGE( 0,31 ); // float } Gen8; struct _Gen9 { DWORD RedClearColor : BITFIELD_RANGE( 0,31 ); // float } Gen9; union _Gen10 { struct _ClearValueAddressEnable { DWORD _Unused : BITFIELD_RANGE( 0, 5 ); // Reserved DWORD ClearColorAddress : BITFIELD_RANGE( 6,31 ); // GraphicsAddress[31:6] } ClearValueAddressEnable; struct _ClearValueAddressDisble { DWORD RedClearColor : BITFIELD_RANGE( 0,31 ); // float } ClearValueAddressDisble; } Gen10; DWORD Value; } DW12; union _DW13 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen9 { DWORD GreenClearColor : BITFIELD_RANGE( 0,31 ); // float } Gen9; union _Gen10 { struct _ClearValueAddressEnable { DWORD _Unused : BITFIELD_RANGE( 0, 15 ); // Reserved DWORD ClearColorAddressHigh : BITFIELD_RANGE( 16,31 ); // GraphicsAddress } ClearValueAddressEnable; struct _ClearValueAddressDisble { DWORD GreenClearColor : BITFIELD_RANGE( 0,31 ); // float } ClearValueAddressDisble; } Gen10; DWORD Value; } DW13; union _DW14 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen9 { DWORD BlueClearColor : BITFIELD_RANGE( 0,31 ); // float } Gen9; union _Gen10 { struct _ClearValueAddressEnable { DWORD _Unused : BITFIELD_RANGE( 0, 31 ); // Reserved } ClearValueAddressEnable; struct _ClearValueAddressDisble { DWORD BlueClearColor : BITFIELD_RANGE( 0,31 ); // float } ClearValueAddressDisble; } Gen10; DWORD Value; } DW14; union _DW15 { struct _All { DWORD Reserved : BITFIELD_RANGE( 0,31 ); // Reserved } All; struct _Gen9 { DWORD AlphaClearColor : BITFIELD_RANGE( 0,31 ); // float } Gen9; union _Gen10 { struct _ClearValueAddressEnable { DWORD _Unused : BITFIELD_RANGE( 0, 31 ); // Reserved } ClearValueAddressEnable; struct _ClearValueAddressDisble { DWORD AlphaClearColor : BITFIELD_RANGE( 0,31 ); // float } ClearValueAddressDisble; } Gen10; DWORD Value; } DW15; }; static_assert(SIZE32(SSharedStateSurfaceState) == 16); /*****************************************************************************\ UNION: SSurfaceStateBufferLength \*****************************************************************************/ union SSurfaceStateBufferLength { struct _All { DWORD Width : BITFIELD_RANGE( 0,6 ); // U7 DWORD Height : BITFIELD_RANGE( 7,19 ); // U13 DWORD Depth : BITFIELD_RANGE( 20,26 ); // U7 DWORD _Unused : BITFIELD_RANGE( 27,31 ); } All; DWORD Length; }; static_assert(SIZE32(SSurfaceStateBufferLength) == 1); } // namespace G6HWC // Reset packing alignment to project default #pragma pack() intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_shared_enum_g8.h000066400000000000000000000736031363533017100276650ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_enum_g8.h" namespace G6HWC { /*****************************************************************************\ CONST: Caps \*****************************************************************************/ const DWORD g_cNumSamplersPerProgram = 16; const DWORD g_cNumSurfacesPerProgram = 252; const DWORD g_cNumSearchPathStatesGen6 = 14; const DWORD g_cNumMBModeSetsGen6 = 4; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_ANISORATIO \*****************************************************************************/ enum GFXSHAREDSTATE_ANISORATIO { GFXSHAREDSTATE_ANISORATIO_2 = 0x0, GFXSHAREDSTATE_ANISORATIO_4 = 0x1, GFXSHAREDSTATE_ANISORATIO_6 = 0x2, GFXSHAREDSTATE_ANISORATIO_8 = 0x3, GFXSHAREDSTATE_ANISORATIO_10 = 0x4, GFXSHAREDSTATE_ANISORATIO_12 = 0x5, GFXSHAREDSTATE_ANISORATIO_14 = 0x6, GFXSHAREDSTATE_ANISORATIO_16 = 0x7 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_CHROMAKEY_MODE \*****************************************************************************/ enum GFXSHAREDSTATE_CHROMAKEY_MODE { GFXSHAREDSTATE_CHROMAKEY_KILL_ON_ANY_MATCH = 0x0, GFXSHAREDSTATE_CHROMAKEY_REPLACE_BLACK = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_CUBECORNERMODE \*****************************************************************************/ enum GFXSHAREDSTATE_CUBECORNERMODE { GFXSHAREDSTATE_CUBECORNERMODE_REPLICATE = 0x0, GFXSHAREDSTATE_CUBECORNERMODE_AVERAGE = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_CUBESURFACECONTROLMODE \*****************************************************************************/ enum GFXSHAREDSTATE_CUBESURFACECONTROLMODE { GFXSHAREDSTATE_CUBESURFACECONTROLMODE_PROGRAMMED = 0x0, GFXSHAREDSTATE_CUBESURFACECONTROLMODE_OVERRIDE = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_DEFAULTCOLOR_MODE \*****************************************************************************/ enum GFXSHAREDSTATE_DEFAULTCOLOR_MODE { GFXSHAREDSTATE_DEFAULTCOLOR_R32G32B32A32_FLOAT = 0, GFXSHAREDSTATE_DEFAULTCOLOR_R8G8B8A8_UNORM = 1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_MAPFILTER \*****************************************************************************/ enum GFXSHAREDSTATE_MAPFILTER { GFXSHAREDSTATE_MAPFILTER_NEAREST = 0x0, GFXSHAREDSTATE_MAPFILTER_LINEAR = 0x1, GFXSHAREDSTATE_MAPFILTER_ANISOTROPIC = 0x2, //GFXSHAREDSTATE_MAPFILTER_RESERVED = 0x3, //GFXSHAREDSTATE_MAPFILTER_RESERVED = 0x4, //GFXSHAREDSTATE_MAPFILTER_RESERVED = 0x5, GFXSHAREDSTATE_MAPFILTER_MONO = 0x6 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_MIPFILTER \*****************************************************************************/ enum GFXSHAREDSTATE_MIPFILTER { GFXSHAREDSTATE_MIPFILTER_NONE = 0x0, GFXSHAREDSTATE_MIPFILTER_NEAREST = 0x1, GFXSHAREDSTATE_MIPFILTER_LINEAR = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_PREFILTER_OPERATION \*****************************************************************************/ enum GFXSHAREDSTATE_PREFILTER_OPERATION { GFXSHAREDSTATE_PREFILTER_ALWAYS = 0x0, GFXSHAREDSTATE_PREFILTER_NEVER = 0x1, GFXSHAREDSTATE_PREFILTER_LESS = 0x2, GFXSHAREDSTATE_PREFILTER_EQUAL = 0x3, GFXSHAREDSTATE_PREFILTER_LEQUAL = 0x4, GFXSHAREDSTATE_PREFILTER_GREATER = 0x5, GFXSHAREDSTATE_PREFILTER_NOTEQUAL = 0x6, GFXSHAREDSTATE_PREFILTER_GEQUAL = 0x7 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_RENDERTARGET_ROTATE \*****************************************************************************/ enum GFXSHAREDSTATE_RENDERTARGET_ROTATE { GFXSHAREDSTATE_RENDERTARGET_ROTATE_0DEG = 0, GFXSHAREDSTATE_RENDERTARGET_ROTATE_90DEG = 1, GFXSHAREDSTATE_RENDERTARGET_ROTATE_270DEG = 3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT \*****************************************************************************/ enum GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT { GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT_BELOW = 0x0, GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT_RIGHT = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_SURFACEFORMAT \*****************************************************************************/ enum GFXSHAREDSTATE_SURFACEFORMAT { GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_FLOAT = 0x000, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_SINT = 0x001, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_UINT = 0x002, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_UNORM = 0x003, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_SNORM = 0x004, GFXSHAREDSTATE_SURFACEFORMAT_R64G64_FLOAT = 0x005, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32X32_FLOAT = 0x006, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_SSCALED = 0x007, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_USCALED = 0x008, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_FLOAT = 0x040, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_SINT = 0x041, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_UINT = 0x042, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_UNORM = 0x043, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_SNORM = 0x044, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_SSCALED = 0x045, GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_USCALED = 0x046, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_UNORM = 0x080, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_SNORM = 0x081, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_SINT = 0x082, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_UINT = 0x083, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_FLOAT = 0x084, GFXSHAREDSTATE_SURFACEFORMAT_R32G32_FLOAT = 0x085, GFXSHAREDSTATE_SURFACEFORMAT_R32G32_SINT = 0x086, GFXSHAREDSTATE_SURFACEFORMAT_R32G32_UINT = 0x087, GFXSHAREDSTATE_SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS = 0x088, GFXSHAREDSTATE_SURFACEFORMAT_X32_TYPELESS_G8X24_UINT = 0x089, GFXSHAREDSTATE_SURFACEFORMAT_L32A32_FLOAT = 0x08A, GFXSHAREDSTATE_SURFACEFORMAT_R32G32_UNORM = 0x08B, GFXSHAREDSTATE_SURFACEFORMAT_R32G32_SNORM = 0x08C, GFXSHAREDSTATE_SURFACEFORMAT_R64_FLOAT = 0x08D, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16X16_UNORM = 0x08E, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16X16_FLOAT = 0x08F, GFXSHAREDSTATE_SURFACEFORMAT_A32X32_FLOAT = 0x090, GFXSHAREDSTATE_SURFACEFORMAT_L32X32_FLOAT = 0x091, GFXSHAREDSTATE_SURFACEFORMAT_I32X32_FLOAT = 0x092, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_SSCALED = 0x093, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_USCALED = 0x094, GFXSHAREDSTATE_SURFACEFORMAT_R32G32_SSCALED = 0x095, GFXSHAREDSTATE_SURFACEFORMAT_R32G32_USCALED = 0x096, GFXSHAREDSTATE_SURFACEFORMAT_B8G8R8A8_UNORM = 0x0C0, GFXSHAREDSTATE_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB = 0x0C1, GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10A2_UNORM = 0x0C2, GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10A2_UNORM_SRGB = 0x0C3, GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10A2_UINT = 0x0C4, GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM = 0x0C5, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UNORM = 0x0C7, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UNORM_SRGB = 0x0C8, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_SNORM = 0x0C9, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_SINT = 0x0CA, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UINT = 0x0CB, GFXSHAREDSTATE_SURFACEFORMAT_R16G16_UNORM = 0x0CC, GFXSHAREDSTATE_SURFACEFORMAT_R16G16_SNORM = 0x0CD, GFXSHAREDSTATE_SURFACEFORMAT_R16G16_SINT = 0x0CE, GFXSHAREDSTATE_SURFACEFORMAT_R16G16_UINT = 0x0CF, GFXSHAREDSTATE_SURFACEFORMAT_R16G16_FLOAT = 0x0D0, GFXSHAREDSTATE_SURFACEFORMAT_B10G10R10A2_UNORM = 0x0D1, GFXSHAREDSTATE_SURFACEFORMAT_B10G10R10A2_UNORM_SRGB = 0x0D2, GFXSHAREDSTATE_SURFACEFORMAT_R11G11B10_FLOAT = 0x0D3, GFXSHAREDSTATE_SURFACEFORMAT_R32_SINT = 0x0D6, GFXSHAREDSTATE_SURFACEFORMAT_R32_UINT = 0x0D7, GFXSHAREDSTATE_SURFACEFORMAT_R32_FLOAT = 0x0D8, GFXSHAREDSTATE_SURFACEFORMAT_R24_UNORM_X8_TYPELESS = 0x0D9, GFXSHAREDSTATE_SURFACEFORMAT_X24_TYPELESS_G8_UINT = 0x0DA, GFXSHAREDSTATE_SURFACEFORMAT_L16A16_UNORM = 0x0DF, GFXSHAREDSTATE_SURFACEFORMAT_I24X8_UNORM = 0x0E0, GFXSHAREDSTATE_SURFACEFORMAT_L24X8_UNORM = 0x0E1, GFXSHAREDSTATE_SURFACEFORMAT_A24X8_UNORM = 0x0E2, GFXSHAREDSTATE_SURFACEFORMAT_I32_FLOAT = 0x0E3, GFXSHAREDSTATE_SURFACEFORMAT_L32_FLOAT = 0x0E4, GFXSHAREDSTATE_SURFACEFORMAT_A32_FLOAT = 0x0E5, GFXSHAREDSTATE_SURFACEFORMAT_B8G8R8X8_UNORM = 0x0E9, GFXSHAREDSTATE_SURFACEFORMAT_B8G8R8X8_UNORM_SRGB = 0x0EA, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8X8_UNORM = 0x0EB, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8X8_UNORM_SRGB = 0x0EC, GFXSHAREDSTATE_SURFACEFORMAT_R9G9B9E5_SHAREDEXP = 0x0ED, GFXSHAREDSTATE_SURFACEFORMAT_B10G10R10X2_UNORM = 0x0EE, GFXSHAREDSTATE_SURFACEFORMAT_L16A16_FLOAT = 0x0F0, GFXSHAREDSTATE_SURFACEFORMAT_R32_UNORM = 0x0F1, GFXSHAREDSTATE_SURFACEFORMAT_R32_SNORM = 0x0F2, GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10X2_USCALED = 0x0F3, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_SSCALED = 0x0F4, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_USCALED = 0x0F5, GFXSHAREDSTATE_SURFACEFORMAT_R16G16_SSCALED = 0x0F6, GFXSHAREDSTATE_SURFACEFORMAT_R16G16_USCALED = 0x0F7, GFXSHAREDSTATE_SURFACEFORMAT_R32_SSCALED = 0x0F8, GFXSHAREDSTATE_SURFACEFORMAT_R32_USCALED = 0x0F9, GFXSHAREDSTATE_SURFACEFORMAT_R8B8G8A8_UNORM = 0x0FA, GFXSHAREDSTATE_SURFACEFORMAT_B5G6R5_UNORM = 0x100, GFXSHAREDSTATE_SURFACEFORMAT_B5G6R5_UNORM_SRGB = 0x101, GFXSHAREDSTATE_SURFACEFORMAT_B5G5R5A1_UNORM = 0x102, GFXSHAREDSTATE_SURFACEFORMAT_B5G5R5A1_UNORM_SRGB = 0x103, GFXSHAREDSTATE_SURFACEFORMAT_B4G4R4A4_UNORM = 0x104, GFXSHAREDSTATE_SURFACEFORMAT_B4G4R4A4_UNORM_SRGB = 0x105, GFXSHAREDSTATE_SURFACEFORMAT_R8G8_UNORM = 0x106, GFXSHAREDSTATE_SURFACEFORMAT_R8G8_SNORM = 0x107, GFXSHAREDSTATE_SURFACEFORMAT_R8G8_SINT = 0x108, GFXSHAREDSTATE_SURFACEFORMAT_R8G8_UINT = 0x109, GFXSHAREDSTATE_SURFACEFORMAT_R16_UNORM = 0x10A, GFXSHAREDSTATE_SURFACEFORMAT_R16_SNORM = 0x10B, GFXSHAREDSTATE_SURFACEFORMAT_R16_SINT = 0x10C, GFXSHAREDSTATE_SURFACEFORMAT_R16_UINT = 0x10D, GFXSHAREDSTATE_SURFACEFORMAT_R16_FLOAT = 0x10E, GFXSHAREDSTATE_SURFACEFORMAT_I16_UNORM = 0x111, GFXSHAREDSTATE_SURFACEFORMAT_L16_UNORM = 0x112, GFXSHAREDSTATE_SURFACEFORMAT_A16_UNORM = 0x113, GFXSHAREDSTATE_SURFACEFORMAT_L8A8_UNORM = 0x114, GFXSHAREDSTATE_SURFACEFORMAT_I16_FLOAT = 0x115, GFXSHAREDSTATE_SURFACEFORMAT_L16_FLOAT = 0x116, GFXSHAREDSTATE_SURFACEFORMAT_A16_FLOAT = 0x117, GFXSHAREDSTATE_SURFACEFORMAT_L8A8_UNORM_SRGB = 0x118, GFXSHAREDSTATE_SURFACEFORMAT_R5G5_SNORM_B6_UNORM = 0x119, GFXSHAREDSTATE_SURFACEFORMAT_B5G5R5X1_UNORM = 0x11A, GFXSHAREDSTATE_SURFACEFORMAT_B5G5R5X1_UNORM_SRGB = 0x11B, GFXSHAREDSTATE_SURFACEFORMAT_R8G8_SSCALED = 0x11C, GFXSHAREDSTATE_SURFACEFORMAT_R8G8_USCALED = 0x11D, GFXSHAREDSTATE_SURFACEFORMAT_R16_SSCALED = 0x11E, GFXSHAREDSTATE_SURFACEFORMAT_R16_USCALED = 0x11F, GFXSHAREDSTATE_SURFACEFORMAT_R8_UNORM = 0x140, GFXSHAREDSTATE_SURFACEFORMAT_R8_SNORM = 0x141, GFXSHAREDSTATE_SURFACEFORMAT_R8_SINT = 0x142, GFXSHAREDSTATE_SURFACEFORMAT_R8_UINT = 0x143, GFXSHAREDSTATE_SURFACEFORMAT_A8_UNORM = 0x144, GFXSHAREDSTATE_SURFACEFORMAT_I8_UNORM = 0x145, GFXSHAREDSTATE_SURFACEFORMAT_L8_UNORM = 0x146, GFXSHAREDSTATE_SURFACEFORMAT_P4A4_UNORM = 0x147, GFXSHAREDSTATE_SURFACEFORMAT_A4P4_UNORM = 0x148, GFXSHAREDSTATE_SURFACEFORMAT_R8_SSCALED = 0x149, GFXSHAREDSTATE_SURFACEFORMAT_R8_USCALED = 0x14A, GFXSHAREDSTATE_SURFACEFORMAT_P8_UNORM = 0x14B, GFXSHAREDSTATE_SURFACEFORMAT_L8_UNORM_SRGB = 0x14C, GFXSHAREDSTATE_SURFACEFORMAT_DXT1_RGB_SRGB = 0x180, GFXSHAREDSTATE_SURFACEFORMAT_R1_UINT = 0x181, GFXSHAREDSTATE_SURFACEFORMAT_YCRCB_NORMAL = 0x182, GFXSHAREDSTATE_SURFACEFORMAT_YCRCB_SWAPUVY = 0x183, GFXSHAREDSTATE_SURFACEFORMAT_P2_UNORM = 0x184, GFXSHAREDSTATE_SURFACEFORMAT_BC1_UNORM = 0x186, GFXSHAREDSTATE_SURFACEFORMAT_BC2_UNORM = 0x187, GFXSHAREDSTATE_SURFACEFORMAT_BC3_UNORM = 0x188, GFXSHAREDSTATE_SURFACEFORMAT_BC4_UNORM = 0x189, GFXSHAREDSTATE_SURFACEFORMAT_BC5_UNORM = 0x18A, GFXSHAREDSTATE_SURFACEFORMAT_BC1_UNORM_SRGB = 0x18B, GFXSHAREDSTATE_SURFACEFORMAT_BC2_UNORM_SRGB = 0x18C, GFXSHAREDSTATE_SURFACEFORMAT_BC3_UNORM_SRGB = 0x18D, GFXSHAREDSTATE_SURFACEFORMAT_MONO8 = 0x18E, GFXSHAREDSTATE_SURFACEFORMAT_YCRCB_SWAPUV = 0x18F, GFXSHAREDSTATE_SURFACEFORMAT_YCRCB_SWAPY = 0x190, GFXSHAREDSTATE_SURFACEFORMAT_DXT1_RGB = 0x191, GFXSHAREDSTATE_SURFACEFORMAT_FXT1 = 0x192, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_UNORM = 0x193, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_SNORM = 0x194, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_SSCALED = 0x195, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_USCALED = 0x196, GFXSHAREDSTATE_SURFACEFORMAT_R64G64B64A64_FLOAT = 0x197, GFXSHAREDSTATE_SURFACEFORMAT_R64G64B64_FLOAT = 0x198, GFXSHAREDSTATE_SURFACEFORMAT_BC4_SNORM = 0x199, GFXSHAREDSTATE_SURFACEFORMAT_BC5_SNORM = 0x19A, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16_UNORM = 0x19C, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16_SNORM = 0x19D, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16_SSCALED = 0x19E, GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16_USCALED = 0x19F, GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_UNORM_SRGB = 0x1A0, GFXSHAREDSTATE_SURFACEFORMAT_BC6H_SF16 = 0x1A1, GFXSHAREDSTATE_SURFACEFORMAT_BC7_UNORM = 0x1A2, GFXSHAREDSTATE_SURFACEFORMAT_BC7_UNORM_SRGB = 0x1A3, GFXSHAREDSTATE_SURFACEFORMAT_BC6H_UF16 = 0x1A4, GFXSHAREDSTATE_SURFACEFORMAT_PLANAR_420_8 = 0x1A5, GFXSHAREDSTATE_SURFACEFORMAT_RAW = 0x1FF, NUM_GFXSHAREDSTATE_SURFACEFORMATS }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_SURFACERETURNFORMAT \*****************************************************************************/ enum GFXSHAREDSTATE_SURFACERETURNFORMAT { GFXSHAREDSTATE_SURFACERETURNFORMAT_FLOAT32 = 0x0, GFXSHAREDSTATE_SURFACERETURNFORMAT_S1_14 = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_SURFACETYPE \*****************************************************************************/ enum GFXSHAREDSTATE_SURFACETYPE { GFXSHAREDSTATE_SURFACETYPE_1D = 0x0, GFXSHAREDSTATE_SURFACETYPE_2D = 0x1, GFXSHAREDSTATE_SURFACETYPE_3D = 0x2, GFXSHAREDSTATE_SURFACETYPE_CUBE = 0x3, GFXSHAREDSTATE_SURFACETYPE_BUFFER = 0x4, GFXSHAREDSTATE_SURFACETYPE_STRBUF = 0x5, //GFXSHAREDSTATE_RESERVED = 0x6, GFXSHAREDSTATE_SURFACETYPE_NULL = 0x7, }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_TEXCOORDMODE \*****************************************************************************/ enum GFXSHAREDSTATE_TEXCOORDMODE { GFXSHAREDSTATE_TEXCOORDMODE_WRAP = 0x0, GFXSHAREDSTATE_TEXCOORDMODE_MIRROR = 0x1, GFXSHAREDSTATE_TEXCOORDMODE_CLAMP = 0x2, GFXSHAREDSTATE_TEXCOORDMODE_CUBE = 0x3, GFXSHAREDSTATE_TEXCOORDMODE_CLAMP_BORDER = 0x4, GFXSHAREDSTATE_TEXCOORDMODE_MIRROR_ONCE = 0x5, GFXSHAREDSTATE_TEXCOORDMODE_MIRROR_101 = 0x7 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_FLEXFILTERMODE \*****************************************************************************/ enum GFXSHAREDSTATE_FLEXFILTERMODE { GFXSHAREDSTATE_FLEXFILTERMODE_SEP = 0x0, GFXSHAREDSTATE_FLEXFILTERMODE_NONSEP = 0x1, }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_TILEWALK \*****************************************************************************/ enum GFXSHAREDSTATE_TILEWALK { GFXSHAREDSTATE_TILEWALK_XMAJOR = 0x0, GFXSHAREDSTATE_TILEWALK_YMAJOR = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_TRILINEAR_QUALITY \*****************************************************************************/ enum GFXSHAREDSTATE_TRILINEAR_QUALITY { GFXSHAREDSTATE_TRILINEAR_QUALITY_FULL = 0x0, GFXSHAREDSTATE_TRILINEAR_QUALITY_HIGH = 0x1, GFXSHAREDSTATE_TRILINEAR_QUALITY_MED = 0x2, GFXSHAREDSTATE_TRILINEAR_QUALITY_LOW = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_TEXTURE_BORDER_COLOR_MODE \*****************************************************************************/ enum GFXSHAREDSTATE_TEXTURE_BORDER_COLOR_MODE { GFXSHAREDSTATE_TEXTURE_BORDER_COLOR_MODE_DX10OGL = 0x0, GFXSHAREDSTATE_TEXTURE_BORDER_COLOR_MODE_DX9 = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_NUM_MULTISAMPLES \*****************************************************************************/ enum GFXSHAREDSTATE_NUM_MULTISAMPLES { GFXSHAREDSTATE_NUMSAMPLES_1 = 0x0, //GFXSHAREDSTATE_RESERVED = 0x1, GFXSHAREDSTATE_NUMSAMPLES_4 = 0x2, GFXSHAREDSTATE_NUMSAMPLES_8 = 0x3 //GFXSHAREDSTATE_RESERVED = 0x4, //GFXSHAREDSTATE_RESERVED = 0x5, //GFXSHAREDSTATE_RESERVED = 0x6, //GFXSHAREDSTATE_RESERVED = 0x7 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_MSFMT \*****************************************************************************/ enum GFXSHAREDSTATE_MSFMT { GFXSHAREDSTATE_MSFMT_MSS = 0x0, GFXSHAREDSTATE_MSFMT_DEPTH_STENCIL = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_CACHEABILITY_CONTROL \*****************************************************************************/ enum GFXSHAREDSTATE_CACHEABILITY_CONTROL { GFXSHAREDSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY = 0x0, GFXSHAREDSTATE_CACHEABILITY_CONTROL_NEITHER_LLC_NOR_MLC = 0x1, GFXSHAREDSTATE_CACHEABILITY_CONTROL_LLC_NOT_MLC = 0x2, GFXSHAREDSTATE_CACHEABILITY_CONTROL_LLC_AND_MLC = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_GRAPHICS_DATATYPE_SOURCE \*****************************************************************************/ enum GFXSHAREDSTATE_GRAPHICS_DATATYPE_SOURCE { GFXSHAREDSTATE_GRAPHICS_DATATYPE_SOURCE_GTT = 0x0, GFXSHAREDSTATE_GRAPHICS_DATATYPE_SOURCE_SURFACE = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_MODE \*****************************************************************************/ enum GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_MODE { GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_NORMAL = 0x0, //GFXSHAREDSTATE_RESERVED = 0x1, GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_PROGRESSIVE_FRAME = 0x2, GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_INTERLACED_FRAME = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_RENDER_CACHE_READ_WRITE_MODE \*****************************************************************************/ enum GFXSHAREDSTATE_RENDER_CACHE_READ_WRITE_MODE { GFXSHAREDSTATE_RENDER_CACHE_WRITE_ONLY_ON_MISS = 0x0, GFXSHAREDSTATE_RENDER_CACHE_READ_WRITE_ONLY_ON_MISS = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_SURFACE_ARRAY_SPACING \*****************************************************************************/ enum GFXSHAREDSTATE_SURFACE_ARRAY_SPACING { GFXSHAREDSTATE_SURFACE_ARRAY_SPACING_FULL = 0x0, GFXSHAREDSTATE_SURFACE_ARRAY_SPACING_LOD0 = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT \*****************************************************************************/ enum GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT { GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT_2 = 0x0, GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT_4 = 0x1, GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT_8 = 0x2, GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT_16 = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_SURFACE_HORIZONTAL_ALIGNMENT \*****************************************************************************/ enum GFXSHAREDSTATE_SURFACE_HORIZONTRAL_ALIGNMENT { GFXSHAREDSTATE_SURFACE_HORIZONTAL_ALIGNMENT_2 = 0x0, GFXSHAREDSTATE_SURFACE_HORIZONTAL_ALIGNMENT_4 = 0x1, GFXSHAREDSTATE_SURFACE_HORIZONTAL_ALIGNMENT_8 = 0x2, GFXSHAREDSTATE_SURFACE_HORIZONTAL_ALIGNMENT_16 = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_RENDER_TARGET_ROTATION \*****************************************************************************/ enum GFXSHAREDSTATE_RENDER_TARGET_ROTATION { GFXSHAREDSTATE_RROTATE_0DEG = 0x0, GFXSHAREDSTATE_RROTATE_90DEG = 0x1, GFXSHAREDSTATE_RROTATE_270DEG = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_L3_CACHEABILITY_CONTROL \*****************************************************************************/ enum GFXSHAREDSTATE_L3_CACHEABILITY_CONTROL { GFXSHAREDSTATE_L3_CACHEABILITY_CONTROL_NOT_CACHEABLE = 0x0, GFXSHAREDSTATE_L3_CACHEABILITY_CONTROL_CACHEABLE = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_LLC_CACHEABILITY_CONTROL \*****************************************************************************/ enum GFXSHAREDSTATE_LLC_CACHEABILITY_CONTROL { GFXSHAREDSTATE_LLC_CACHEABILITY_CONTROL_USE_GTT_ENTRY = 0x0, GFXSHAREDSTATE_LLC_CACHEABILITY_CONTROL_CACHEABLE = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_CLEARCOLOR \*****************************************************************************/ enum GFXSHAREDSTATE_CLEARCOLOR { GFXSHAREDSTATE_CLEARCOLOR_ZERO = 0x0, GFXSHAREDSTATE_CLEARCOLOR_ONE = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_SHADERCHANNELSELECT \*****************************************************************************/ enum GFXSHAREDSTATE_SHADERCHANNELSELECT { GFXSHAREDSTATE_SHADERCHANNELSELECT_ZERO = 0x0, GFXSHAREDSTATE_SHADERCHANNELSELECT_ONE = 0x1, GFXSHAREDSTATE_SHADERCHANNELSELECT_RED = 0x4, GFXSHAREDSTATE_SHADERCHANNELSELECT_GREEN = 0x5, GFXSHAREDSTATE_SHADERCHANNELSELECT_BLUE = 0x6, GFXSHAREDSTATE_SHADERCHANNELSELECT_ALPHA = 0x7 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_TILEMODE \*****************************************************************************/ enum GFXSHAREDSTATE_TILEMODE { GFXSHAREDSTATE_TILEMODE_LINEAR = 0x0, GFXSHAREDSTATE_TILEMODE_WMAJOR = 0x1, GFXSHAREDSTATE_TILEMODE_XMAJOR = 0x2, GFXSHAREDSTATE_TILEMODE_YMAJOR = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_REDUCTION_TYPE \*****************************************************************************/ enum GFXSHAREDSTATE_REDUCTION_TYPE { GFXSHAREDSTATE_STD_FILTER = 0x0, GFXSHAREDSTATE_COMPARISON = 0x1, GFXSHAREDSTATE_MINIMUM = 0x2, GFXSHAREDSTATE_MAXIMUM = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_COHERENCY_TYPE \*****************************************************************************/ enum GFXSHAREDSTATE_COHERENCY_TYPE { GFXSHAREDSTATE_NON_COHERENT = 0x0, GFXSHAREDSTATE_IA_CHERENT = 0x1 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_TILED_RESOURCE_HORIZONTAL_ALIGNMENT \*****************************************************************************/ enum GFXSHAREDSTATE_TILED_RESOURCE_HORIZONTAL_ALIGNMENT { GFXSHAREDSTATE_TILED_RESOURCE_HORIZONTAL_ALIGNMENT_64 = 0x0, GFXSHAREDSTATE_TILED_RESOURCE_HORIZONTAL_ALIGNMENT_128 = 0x1, GFXSHAREDSTATE_TILED_RESOURCE_HORIZONTAL_ALIGNMENT_256 = 0x2, GFXSHAREDSTATE_TILED_RESOURCE_HORIZONTAL_ALIGNMENT_512 = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_TILED_RESOURCE_VERTICAL_ALIGNMENT \*****************************************************************************/ enum GFXSHAREDSTATE_TILED_RESOURCE_VERTICAL_ALIGNMENT { GFXSHAREDSTATE_TILED_RESOURCE_VERTICAL_ALIGNMENT_64 = 0x0, GFXSHAREDSTATE_TILED_RESOURCE_VERTICAL_ALIGNMENT_128 = 0x1, GFXSHAREDSTATE_TILED_RESOURCE_VERTICAL_ALIGNMENT_256 = 0x2, GFXSHAREDSTATE_TILED_RESOURCE_VERTICAL_ALIGNMENT_512 = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_AUXILIARY_SURFACE_MODE \*****************************************************************************/ enum GFXSHAREDSTATE_AUXILIARY_SURFACE_MODE { GFXSHAREDSTATE_AUX_NONE = 0x0, GFXSHAREDSTATE_AUX_CCS = 0x1, GFXSHAREDSTATE_AUX_APPEND = 0x2, GFXSHAREDSTATE_AUX_HIZ = 0x3 }; /*****************************************************************************\ ENUM: GFXSHAREDSTATE_MAPFILTER \*****************************************************************************/ enum GFXSHAREDSTATE_ANISOTROPIC_ALGORITHM { GFXSHAREDSTATE_ANISOTROPIC_LEGACY = 0x0, GFXSHAREDSTATE_ANISOTROPIC_EWA_APPROXIMATION = 0x1 }; } // namespace G6HWCintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Platform/cmd_shared_init_g8.h000066400000000000000000001162301363533017100276560ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cmd_shared_enum_g8.h" #include "cmd_shared_def_g8.h" namespace G6HWC { /*****************************************************************************\ CONST: SSharedStateBindingTableState \*****************************************************************************/ static const SSharedStateBindingTableState g_cInitSharedStateBindingTableState = { // DW0 { { 0, // _Unused 0 // SurfaceStatePointer } } }; /*****************************************************************************\ CONST: g_cInitGfxSamplerIndirectState \*****************************************************************************/ static const SGfxSamplerIndirectState g_cInitGfxSamplerIndirectState = { 0.0f, 0.0f, 0.0f, 0.0f, // Border Colors RGBA 0, 0, 0, 0, 0, 0, 0, 0 // Unused DWORDS 4-11 }; /*****************************************************************************\ CONST: g_cInitSamplerState \*****************************************************************************/ static const SSharedStateSamplerState g_cInitSharedStateSamplerState = { // DWORD 0 { { GFXSHAREDSTATE_PREFILTER_ALWAYS, // ShadowFunction 0, // TextureLODBias GFXSHAREDSTATE_MAPFILTER_NEAREST, // MinModeFilter GFXSHAREDSTATE_MAPFILTER_NEAREST, // MagModeFilter GFXSHAREDSTATE_MIPFILTER_NONE, // MipModeFilter 0, // BaseMipLevel 0, // _Unused1 false, // LODPreClampEnable GFXSHAREDSTATE_DEFAULTCOLOR_R32G32B32A32_FLOAT, // TextureBorderColorMode 0, // _Unused2 true // SamplerDisable } }, // DWORD 1 { { GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCZAddressControlMode GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCYAddressControlMode GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCXAddressControlMode GFXSHAREDSTATE_CUBESURFACECONTROLMODE_OVERRIDE, // CubeSurfaceControlMode 0, // _Unused 0, // MaxLOD 0 // MinLOD } }, // DWORD 2 { { 0, // _Unused 0 // BorderColorPointer } }, // DWORD 3, { { false, // NonNormalizedCoordinatesEnable 0, // _Unused1 false, // RAddressMinFilterAddressRoundingEnable false, // RAddressMagFilterAddressRoundingEnable false, // VAddressMinFilterAddressRoundingEnable false, // VAddressMagFilterAddressRoundingEnable false, // UAddressMinFilterAddressRoundingEnable false, // UAddressMagFilterAddressRoundingEnable GFXSHAREDSTATE_ANISORATIO_2, // MaximumAnisotropy GFXSHAREDSTATE_CHROMAKEY_KILL_ON_ANY_MATCH, // ChromaKeyMode 0, // ChromaKeyIndex false, // ChromaKeyEnable 0 // _Unused2 } } }; /*****************************************************************************\ CONST: g_cInitSamplerStateDW0Gen7 \*****************************************************************************/ static const SSharedStateSamplerState::_DW0::_Gen7 g_cInitSharedStateSamplerStateDW0Gen7 = { 0, // _Unused1 0, // TextureLODBias GFXSHAREDSTATE_MAPFILTER_NEAREST, // MinModeFilter GFXSHAREDSTATE_MAPFILTER_NEAREST, // MagModeFilter GFXSHAREDSTATE_MIPFILTER_NONE, // MipModeFilter 0, // BaseMipLevel 0, // _Unused2 false, // LODPreClampEnable GFXSHAREDSTATE_DEFAULTCOLOR_R32G32B32A32_FLOAT, // TextureBorderColorMode 0, // _Unused3 true // SamplerDisable }; /*****************************************************************************\ CONST: g_cInitSamplerStateDW0Gen9 \*****************************************************************************/ static const SSharedStateSamplerState::_DW0::_Gen9 g_cInitSharedStateSamplerStateDW0Gen9 = { GFXSHAREDSTATE_ANISOTROPIC_LEGACY, // AnisotropicAlgorithm 0, // TextureLODBias GFXSHAREDSTATE_MAPFILTER_NEAREST, // MinModeFilter GFXSHAREDSTATE_MAPFILTER_NEAREST, // MagModeFilter GFXSHAREDSTATE_MIPFILTER_NONE, // MipModeFilter 0, // CoarseLODQualityMode 0, // _Unused1 false, // LODPreClampEnable GFXSHAREDSTATE_DEFAULTCOLOR_R32G32B32A32_FLOAT, // TextureBorderColorMode 0, // _Unused2 true // SamplerDisable }; /*****************************************************************************\ CONST: g_cInitSamplerStateDW1Gen7 \*****************************************************************************/ static const SSharedStateSamplerState::_DW1::_Gen7 g_cInitSharedStateSamplerStateDW1Gen7 = { GFXSHAREDSTATE_CUBESURFACECONTROLMODE_OVERRIDE, // CubeSurfaceControlMode GFXSHAREDSTATE_PREFILTER_ALWAYS, // ShadowFunction 0, // _Unused 0, // MaxLOD 0 // MinLOD }; /*****************************************************************************\ CONST: g_cInitSamplerStateDW3Gen7 \*****************************************************************************/ static const SSharedStateSamplerState::_DW3::_Gen7 g_cInitSharedStateSamplerStateDW3Gen7 = { GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCZAddressControlMode GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCYAddressControlMode GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCXAddressControlMode 0, // _Unused1 false, // NonnormalizedCoordinateEnable GFXSHAREDSTATE_TRILINEAR_QUALITY_LOW, // TrilinearFilterQuality false, // RAddressMinFilterAddressRoundingEnable false, // RAddressMagFilterAddressRoundingEnable false, // VAddressMinFilterAddressRoundingEnable false, // VAddressMagFilterAddressRoundingEnable false, // UAddressMinFilterAddressRoundingEnable false, // UAddressMagFilterAddressRoundingEnable GFXSHAREDSTATE_ANISORATIO_2, // MaximumAnisotropy GFXSHAREDSTATE_CHROMAKEY_KILL_ON_ANY_MATCH, // ChromaKeyMode 0, // ChromaKeyIndex false, // ChromaKeyEnable 0 // _Unused2 }; /*****************************************************************************\ CONST: g_cInitSamplerStateDW3Gen9 \*****************************************************************************/ static const SSharedStateSamplerState::_DW3::_Gen9 g_cInitSharedStateSamplerStateDW3Gen9 = { GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCZAddressControlMode GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCYAddressControlMode GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // TCXAddressControlMode false, // ReductionTypeEnable false, // NonNormalizedCoordinateEnable GFXSHAREDSTATE_TRILINEAR_QUALITY_LOW, // TrilinearFilterQuality false, // RAddressMinFilterAddressRoundingEnable false, // RAddressMagFilterAddressRoundingEnable false, // VAddressMinFilterAddressRoundingEnable false, // VAddressMagFilterAddressRoundingEnable false, // UAddressMinFilterAddressRoundingEnable false, // UAddressMagFilterAddressRoundingEnable GFXSHAREDSTATE_ANISORATIO_2, // MaximumAnisotropy GFXSHAREDSTATE_STD_FILTER, // ReductionType 0 // NonSeparableFilterFootprintMask }; /*****************************************************************************\ CONST: g_cInitVmeState \*****************************************************************************/ static const SSharedStateSearchPathLUTState::_DW0::_Byte g_cInitSharedSearchPathLUTStates[ g_cNumSearchPathStatesGen6 ] = { { 0x01,0x01,0x01,0x01 }, // 0 { 0x01,0x01,0x01,0x10 }, // 1 { 0x0F,0x0F,0x0F,0x0F }, // 2 { 0x0F,0x0F,0x0F,0x10 }, // 3 { 0x01,0x01,0x01,0x01 }, // 4 { 0x01,0x01,0x01,0x10 }, // 5 { 0x0F,0x0F,0x0F,0x0F }, // 6 { 0x0F,0x0F,0x0F,0x10 }, // 7 { 0x01,0x01,0x01,0x01 }, // 8 { 0x01,0x01,0x01,0x10 }, // 9 { 0x0F,0x0F,0x0F,0x0F }, // 10 { 0x0F,0x0F,0x0F,0x00 }, // 11 { 0x00,0x00,0x00,0x00 }, // 12 { 0x00,0x00,0x00,0x00 } // 13 }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceState \*****************************************************************************/ static const SSharedStateSurfaceState g_cInitSharedStateSurfaceState = { // DWORD 0 { { 0, // CubeFaceEnablesPositiveZ 0, // CubeFaceEnablesNegativeZ 0, // CubeFaceEnablesPositiveY 0, // CubeFaceEnablesNegativeY 0, // CubeFaceEnablesPositiveX 0, // CubeFaceEnablesNegativeX GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_NORMAL, // MediaBoundaryPixelMode GFXSHAREDSTATE_RENDER_CACHE_WRITE_ONLY_ON_MISS, // RenderCacheReadWriteMode GFXSHAREDSTATE_CUBECORNERMODE_REPLICATE, // CubeMapCornerMode GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT_BELOW, // MipMapLayoutMode 0, // VerticalLineStrideOffset 0, // VerticalLineStride 0, // _Unused1 GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UNORM, // SurfaceFormat GFXSHAREDSTATE_SURFACERETURNFORMAT_FLOAT32, // DataReturnFormat 0, // _Unused2 GFXSHAREDSTATE_SURFACETYPE_NULL // SurfaceType } }, // DWORD 1 { { 0 // SurfaceBaseAddress } }, // DWORD 2 { { GFXSHAREDSTATE_RENDERTARGET_ROTATE_0DEG, // RenderTargetRotation 0, // MipCount 0, // Width 0 // Height } }, // DWORD 3 { { GFXSHAREDSTATE_TILEWALK_YMAJOR, // TileWalk false, // TiledSurface 0, // _Unused1 0, // SurfacePitch 0, // _Unused2 0 // Depth } }, // DWORD 4 { { 0, // MultisamplePositionPaletteIndex 0, // _Unused1 GFXSHAREDSTATE_NUMSAMPLES_1, // NumMultisamples 0, // _Unused2 0, // RenderTargetViewExtent 0, // MinimumArrayElement 0 // SurfaceMinLOD } }, // DWORD 5 { { 0, // _Unused GFXSHAREDSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // SurfaceCacheabilityControl GFXSHAREDSTATE_GRAPHICS_DATATYPE_SOURCE_GTT, // SurfaceGraphicsDataType false, // SurfaceEncryptedDataEnable 0, // YOffset GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT_2, // SurfaceVerticalAlignment 0 // XOffset } }, // DWORD 6 { { 0 // Reserved } }, // DWORD 7 { { 0 // Reserved } }, // DWORD 8 { { 0 // Reserved } }, // DWORD 9 { { 0 // Reserved } }, // DWORD 10 { { 0 // Reserved } }, // DWORD 11 { { 0 // Reserved } }, // DWORD 12 { { 0 // Reserved } }, // DWORD 13 { { 0 // Reserved } }, // DWORD 14 { { 0 // Reserved } }, // DWORD 15 { { 0 // Reserved } } }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW0Gen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW0::_Gen7 g_cInitSharedStateSurfaceStateDW0Gen7 = { 0, // CubeFaceEnablesPositiveZ 0, // CubeFaceEnablesNegativeZ 0, // CubeFaceEnablesPositiveY 0, // CubeFaceEnablesNegativeY 0, // CubeFaceEnablesPositiveX 0, // CubeFaceEnablesNegativeX GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_NORMAL, // MediaBoundaryPixelMode GFXSHAREDSTATE_RENDER_CACHE_WRITE_ONLY_ON_MISS, // RenderCacheReadWriteMode 0, // _Unused1 GFXSHAREDSTATE_SURFACE_ARRAY_SPACING_FULL, // SurfaceArraySpacing 0, // VerticalLineStrideOffset 0, // VerticalLineStride GFXSHAREDSTATE_TILEWALK_YMAJOR, // TileWalk false, // TiledSurface 0, // _Unused2 GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UNORM, // SurfaceFormat 0, // _Unused3 false, // SurfaceArray GFXSHAREDSTATE_SURFACETYPE_NULL // SurfaceType }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW0Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW0::_Gen8 g_cInitSharedStateSurfaceStateDW0Gen8 = { 0, // CubeFaceEnablesPositiveZ 0, // CubeFaceEnablesNegativeZ 0, // CubeFaceEnablesPositiveY 0, // CubeFaceEnablesNegativeY 0, // CubeFaceEnablesPositiveX 0, // CubeFaceEnablesNegativeX GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_NORMAL, // MediaBoundaryPixelMode GFXSHAREDSTATE_RENDER_CACHE_WRITE_ONLY_ON_MISS, // RenderCacheReadWriteMode 0, // SurfaceArraySpace 0, // VerticalLineStrideOffset 0, // VerticalLineStride GFXSHAREDSTATE_TILEMODE_YMAJOR, // TileMode GFXSHAREDSTATE_SURFACE_HORIZONTAL_ALIGNMENT_16, // SurfaceHorizontalAlignment GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT_16, // SurfaceVerticalAlignment GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UNORM, // SurfaceFormat 0, // _Unused false, // SurfaceArray GFXSHAREDSTATE_SURFACETYPE_NULL // SurfaceType }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW0Gen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW0::_Gen9 g_cInitSharedStateSurfaceStateDW0Gen9 = { 0, // CubeFaceEnablesPositiveZ 0, // CubeFaceEnablesNegativeZ 0, // CubeFaceEnablesPositiveY 0, // CubeFaceEnablesNegativeY 0, // CubeFaceEnablesPositiveX 0, // CubeFaceEnablesNegativeX GFXSHAREDSTATE_MEDIA_BOUNDARY_PIXEL_NORMAL, // MediaBoundaryPixelMode GFXSHAREDSTATE_RENDER_CACHE_WRITE_ONLY_ON_MISS, // RenderCacheReadWriteMode 0, // SurfaceArraySpace 0, // VerticalLineStrideOffset 0, // VerticalLineStride GFXSHAREDSTATE_TILEMODE_YMAJOR, // TileMode GFXSHAREDSTATE_SURFACE_HORIZONTAL_ALIGNMENT_16, // SurfaceHorizontalAlignment GFXSHAREDSTATE_SURFACE_VERTICAL_ALIGNMENT_16, // SurfaceVerticalAlignment GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UNORM, // SurfaceFormat false, // ASTCEnable false, // SurfaceArray GFXSHAREDSTATE_SURFACETYPE_NULL // SurfaceType }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW1Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW1::_Gen8 g_cInitSharedStateSurfaceStateDW1Gen8 = { 0, // SurfaceQPitch 0, // _Unused1 GFXSTATE_SOURCE_AGE_CONTROL_BEST_HIT_CHANCE, // SurfaceObjectAgeControl false, // EncryptedData GFXSTATE_TARGET_CACHE_ELLC_ONLY, // TargetCache GFXSTATE_CACHEABILITY_CONTROL_USE_GTT_ENTRY, // CacheabilityControl 0 // _Unused2 }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW2Gen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW2::_Gen7 g_cInitSharedStateSurfaceStateDW2Gen7 = { 0, // Width 0, // _Unused1 0, // Height 0 // _Unused2 }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW2AdvGen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW2::_Gen7_Media g_cInitSharedStateSurfaceStateDW2AdvGen7 = { GFXSHAREDSTATE_TILEWALK_XMAJOR, // TileWalk 0, // TiledSurface 0, // HalfPitchforChroma 0, // SurfacePitch 0, // _Unused1 0, // SurfaceObjectControlState 0, // _Unused2 0, // InterleaveChroma 0 // MEDIASTATE_SURFACEFORMAT_YCRCB_NORMAL // SurfaceFormat }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW3Gen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW3::_Gen7 g_cInitSharedStateSurfaceStateDW3Gen7 = { 0, // SurfacePitch 0, // _Unused 0 // Depth }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW4Gen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW4::_Gen7 g_cInitSharedStateSurfaceStateDW4Gen7 = { { 0, // MultisamplePositionPaletteIndex GFXSHAREDSTATE_NUMSAMPLES_1, // NumMultisamples GFXSHAREDSTATE_MSFMT_MSS, // MultisampledSurfaceStorageFormat 0, // RenderTargetViewExtent 0, // MinimumArrayElement GFXSHAREDSTATE_RROTATE_0DEG, // RenderTargetRotation 0 // _Unused } }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW5Gen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW5::_Gen7 g_cInitSharedStateSurfaceStateDW5Gen7 = { 0, // MIPCountLOD 0, // SurfaceMinLOD 0, // _Unused1 GFXSHAREDSTATE_L3_CACHEABILITY_CONTROL_NOT_CACHEABLE,// CacheabilityControlL3 GFXSHAREDSTATE_LLC_CACHEABILITY_CONTROL_USE_GTT_ENTRY,// CacheabilityControlLLC GFXSTATE_GFDT_SOURCE_GTT, // SurfaceGraphicsDataType false, // SurfaceEncryptedDataEnable 0, // YOffset 0, // _Unused2 0 // XOffset }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW5Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW5::_Gen8 g_cInitSharedStateSurfaceStateDW5Gen8 = { 0, // MIPCountLOD 0, // SurfaceMinLOD 0, // _Unused1 0, // YOffset 0, // _Unused2 0 // XOffset }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW5Gen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW5::_Gen9 g_cInitSharedStateSurfaceStateDW5Gen9 = { 0, // MIPCountLOD 0, // SurfaceMinLOD 0, // MipTailStartLOD 0, // _Unused1 GFXSHAREDSTATE_NON_COHERENT, // GFXSHAREDSTATE_COHERENCY_TYPE GFXSHAREDSTATE_TILED_RESOURCE_VERTICAL_ALIGNMENT_64, // GFXSHAREDSTATE_TILED_RESOURCE_VERTICAL_ALIGNMENT GFXSHAREDSTATE_TILED_RESOURCE_HORIZONTAL_ALIGNMENT_64, // GFXSHAREDSTATE_TILED_RESOURCE_HORIZONTAL_ALIGNMENT false, // TiledResourceEnable 0, // _Unused2 0, // YOffset 0, // _Unused3 0 // XOffset }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW6MCSGen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW6::_Gen7::_SurfaceMCS g_cInitSharedStateSurfaceStateDW6MCSGen7 = { false, // MCSEnable 0, // _Unused 0, // MCSSurfacePitch 0 // MCSBaseAddress }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW6AppendCounterGen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW6::_Gen7::_SurfaceAppendCounter g_cInitSharedStateSurfaceStateDW6AppendCounterGen7 = { false, // AppendCounterEnable 0, // _Unused 0 // AppendCounterAddress }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW6SurfacePlanarGen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW6::_Gen9::_SurfacePlanar g_cInitSharedStateSurfaceStateDW6SurfacePlanarGen9 = { 0, // YOffset 0, // _Unused1 0, // XOffset 0 // _Unused2 }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW6SurfaceOtherGen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW6::_Gen9::_SurfaceOther g_cInitSharedStateSurfaceStateDW6SurfaceOtherGen9 = { GFXSHAREDSTATE_AUX_NONE, // GFXSHAREDSTATE_AUXILIARY_SURFACE_MODE false, // RenderTargetCompressionEnable 0, // AuxiliarySurfacePitch 0, // _Unused1 0, // AuxilarySurfaceQPitch 0 // _Unused2 }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW7Gen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW7::_Gen7 g_cInitSharedStateSurfaceStateDW7Gen7 = { 0, // ResourceMinLOD 0, // _Unused GFXSHAREDSTATE_CLEARCOLOR_ZERO, // AlphaClearColor GFXSHAREDSTATE_CLEARCOLOR_ZERO, // BlueClearColor GFXSHAREDSTATE_CLEARCOLOR_ZERO, // GreenClearColor GFXSHAREDSTATE_CLEARCOLOR_ZERO // RedClearColor }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW7Gen7 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW7::_Gen7_5 g_cInitSharedStateSurfaceStateDW7Gen7_5 = { 0, // ResourceMinLOD 0, // _Unused GFXSHAREDSTATE_SHADERCHANNELSELECT_ALPHA, // ShaderChannelSelectA GFXSHAREDSTATE_SHADERCHANNELSELECT_BLUE, // ShaderChannelSelectB GFXSHAREDSTATE_SHADERCHANNELSELECT_GREEN, // ShaderChannelSelectG GFXSHAREDSTATE_SHADERCHANNELSELECT_RED, // ShaderChannelSelectR GFXSHAREDSTATE_CLEARCOLOR_ZERO, // AlphaClearColor GFXSHAREDSTATE_CLEARCOLOR_ZERO, // BlueClearColor GFXSHAREDSTATE_CLEARCOLOR_ZERO, // GreenClearColor GFXSHAREDSTATE_CLEARCOLOR_ZERO // RedClearColor }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW7Gen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW7::_Gen9 g_cInitSharedStateSurfaceStateDW7Gen9 = { 0, // ResourceMinLOD 0, // _Unused1 GFXSHAREDSTATE_SHADERCHANNELSELECT_ALPHA, // ShaderChannelSelectA GFXSHAREDSTATE_SHADERCHANNELSELECT_BLUE, // ShaderChannelSelectB GFXSHAREDSTATE_SHADERCHANNELSELECT_GREEN, // ShaderChannelSelectG GFXSHAREDSTATE_SHADERCHANNELSELECT_RED, // ShaderChannelSelectR 0 // _Unused2 }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW8Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW8::_Gen8 g_cInitSharedStateSurfaceStateDW8Gen8 = { 0 // SurfaceBaseAddress }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW9Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW9::_Gen8 g_cInitSharedStateSurfaceStateDW9Gen8 = { 0, // Surface64bitBaseAddress 0 // _Unused }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW10Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW10::_Gen8 g_cInitSharedStateSurfaceStateDW10Gen8 = { 0 // AuxiliarySurfaceBaseAddress }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW10Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW10::_Gen9::_SurfaceOther g_cInitSharedStateSurfaceStateDW10SurfaceOtherGen9 = { 0, // QuiltWidth 0, // QuiltHeight 0, // _Unused 0 // AuxiliarySurfaceBaseAddress }; static const SSharedStateSurfaceState::_DW10::_Gen9::_SurfacePlanar g_cInitSharedStateSurfaceStateDW10SurfacePlanarGen9 = { 0, // QuiltWidth 0, // QuiltHeight 0 // _Unused }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW11Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW11::_Gen8 g_cInitSharedStateSurfaceStateDW11Gen8 = { 0, // Auxiliary64bitBaseAddress 0 // _Unused }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW12Gen8 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW12::_Gen8 g_cInitSharedStateSurfaceStateDW12Gen8 = { 0 // HierarchicalDepthClearValue }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW12Gen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW12::_Gen9 g_cInitSharedStateSurfaceStateDW12Gen9 = { GFXSHAREDSTATE_CLEARCOLOR_ZERO // RedClearColor }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW13Gen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW13::_Gen9 g_cInitSharedStateSurfaceStateDW13Gen9 = { GFXSHAREDSTATE_CLEARCOLOR_ZERO // GreenClearColor }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW14Gen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW14::_Gen9 g_cInitSharedStateSurfaceStateDW14Gen9 = { GFXSHAREDSTATE_CLEARCOLOR_ZERO // BlueClearColor; }; /*****************************************************************************\ CONST: g_cInitSharedStateSurfaceStateDW15Gen9 \*****************************************************************************/ static const SSharedStateSurfaceState::_DW15::_Gen9 g_cInitSharedStateSurfaceStateDW15Gen9 = { GFXSHAREDSTATE_CLEARCOLOR_ZERO // AlphaClearColor }; /*****************************************************************************\ CONST: g_cInitSSurfaceStateBufferLength \*****************************************************************************/ static const SSurfaceStateBufferLength g_cInitSurfaceStateBufferLength = { //DWORD 0 { 0, // Width 0, // Height 0, // Depth 0 // _Unused } }; } // namespace G6HWC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Resource/000077500000000000000000000000001363533017100237735ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Resource/BuiltinResource.h000066400000000000000000000030151363533017100272610ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //{{NO_DEPENDENCIES}} // Used by BuiltinResource.rc // #define OCL_BC_START 120 #define OCL_BC_32 120 #define OCL_BC_64 121 #define OCL_BC 122 #define OCL_BC_RS 123 #define OCL_BC_END 124 intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/Resource/BuiltinResource.rc000066400000000000000000000031041363533017100274350ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "BuiltinResource.h" ///////////////////////////////////////////////////////////////////////////// // // BC // OCL_BC BC "OCLBiFImpl.bc" OCL_BC_32 BC "IGCsize_t_32.bc" OCL_BC_64 BC "IGCsize_t_64.bc" ///////////////////////////////////////////////////////////////////////////// intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/TB/000077500000000000000000000000001363533017100225115ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/TB/igc_tb.h000066400000000000000000000053071363533017100241160ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "TranslationBlock.h" #include "Compiler/CodeGenPublic.h" #include "gtsysinfo.h" namespace TC { /*****************************************************************************\ Class: CICBETranslationBlock Description: \*****************************************************************************/ class CIGCTranslationBlock : public CTranslationBlock { public: static bool Create( const STB_CreateArgs* pCreateArgs, CIGCTranslationBlock* &pTranslationBlock ); static void Delete( CIGCTranslationBlock* &pTranslationBlock ); virtual bool Translate( const STB_TranslateInputArgs* pInputArgs, STB_TranslateOutputArgs* pOutputArgs ); virtual bool FreeAllocations( STB_TranslateOutputArgs* pOutputArgs ); protected: CIGCTranslationBlock( void ); virtual ~CIGCTranslationBlock( void ); bool Initialize( const STB_CreateArgs* pCreateArgs ); bool ProcessElfInput( STB_TranslateInputArgs &InputArgs, STB_TranslateOutputArgs &OutputArgs, IGC::OpenCLProgramContext &Context); // State PLATFORM m_Platform; SKU_FEATURE_TABLE m_SkuTable; GT_SYSTEM_INFO m_SysInfo; // Type of input TB_DATA_FORMAT m_DataFormatInput; TB_DATA_FORMAT m_DataFormatOutput; float m_ProfilingTimerResolution; }; } // namespace TC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/000077500000000000000000000000001363533017100226265ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/gtpin_igc_ocl.cpp000066400000000000000000000170061363533017100261360ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "gtpin_igc_ocl.h" #if !defined(_WIN32) #define _strdup strdup #endif #include "Probe.h" // // We need to make the following functions that will be replaced by GT-Pin at runtime // a little more complex to prevent the compiler from optimizing them (apparently, // the compiler did perform some link-time optimization on these functions). // static volatile bool gtpinIsEnabled = false; MY_EXTERN_C MY_DLLEXPORT bool MY_CALLINGSTD GTPIN_IGC_OCL_IsEnabled() { return gtpinIsEnabled; } MY_EXTERN_C MY_DLLEXPORT void MY_CALLINGSTD GTPIN_IGC_OCL_SetEnabled(const bool x) { gtpinIsEnabled = x; } MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_NumberOfSurfaces() { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return 1; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_UpdateKernelInfo(const unsigned kernelBinarySize, const int scratchSurfBti, const int pBufBti ) { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return 2; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_GetSurfaceBTI( const int i ) { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return 3; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_GetEnqueueInstanceKernelArgNo() { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return 4; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_GetSurfaceKernelArgNo( const int i ) { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return 5; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_CompilerReservedRegs( const char* regNames ) { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return 6; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT char* MY_CALLINGSTD GTPIN_IGC_OCL_GetCommandLine() { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return (char*)7; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT GTPIN_INVOKE_STRUCT* MY_CALLINGSTD GTPIN_IGC_OCL_GetInvokeStruct() { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return (GTPIN_INVOKE_STRUCT*)8; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_FillAllKernelsInfo() { // This function body will be replaced by Pin at runtime if GT-Pin is used. if (GTPIN_IGC_OCL_IsEnabled()) { IGC_ASSERT(0); return 9; } else { return 0; } } MY_EXTERN_C MY_DLLEXPORT GEN_ISA_TYPE MY_CALLINGSTD GTPIN_IGC_OCL_GetGenIsaFromPlatform( PLATFORM platform ) { switch ( platform.eRenderCoreFamily ) { case IGFX_GEN7_CORE: return GEN_ISA_TYPE_GEN7; case IGFX_GEN7_5_CORE: return GEN_ISA_TYPE_GEN7p5; case IGFX_GEN8_CORE: return GEN_ISA_TYPE_GEN8; case IGFX_GEN9_CORE: return GEN_ISA_TYPE_GEN9; case IGFX_GEN10_CORE: return GEN_ISA_TYPE_GEN10; default: IGC_ASSERT(0); return GEN_ISA_TYPE_INVALID; } } MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_Instrument( const GEN_ISA_TYPE genIsa, const char* driverVersionStr, const int originalBinarySize, void* originalBinaryOutput, int &instrumentedBinarySize, void*& instrumentedBinaryOutput) { bool success = true; GTPIN_INVOKE_STRUCT* gtpinInvokeStruct = GTPIN_IGC_OCL_GetInvokeStruct(); success = ( gtpinInvokeStruct != NULL ); INVOKE_GTPIN_PROC funInvokingGTPin = 0; if( success ) { funInvokingGTPin = (INVOKE_GTPIN_PROC) gtpinInvokeStruct->_args[ GTPIN_INVOKE_STRUCT_ARG_POS_FUNPTR ]; const int res = GTPIN_IGC_OCL_FillAllKernelsInfo(); // use the result of GTPIN_IGC_OCL_FillAllKernelsInfo() to make sure that the compiler won't optimize this call away success = ( res == 0 ); } char* driverVersionDup = 0; if( success ) { // pass the driver-version string to GT-Pin driverVersionDup = (char*)_strdup(driverVersionStr); success = ( driverVersionDup != NULL ); } if( success ) { gtpinInvokeStruct->_args[ GTPIN_INVOKE_STRUCT_ARG_POS_DRIVERVERSION ] = driverVersionDup; // driverVersionDup will be freed inside funInvokingGTPin() gtpinInvokeStruct->_args[ GTPIN_INVOKE_STRUCT_ARG_POS_OCLDEBUGDATA ] = NULL; // no debug data for now with IGC gtpinInvokeStruct->_args[ GTPIN_INVOKE_STRUCT_ARG_POS_OCLDEBUGSIZE ] = reinterpret_cast< void * >(0); // no debug data for now with IGC char* gtpinCommandLine = GTPIN_IGC_OCL_GetCommandLine(); char* resultMsg = 0; // Invoke the GT-Pin binary rewriter success = funInvokingGTPin( genIsa, originalBinaryOutput, originalBinarySize, gtpinCommandLine, gtpinInvokeStruct, -1, // not used -1, // not used -1, // not used instrumentedBinaryOutput, instrumentedBinarySize, resultMsg ); } if( success ) { return 0; } else { return -1; } } MY_EXTERN_C MY_DLLEXPORT uint64_t MY_CALLINGSTD GTPIN_IGC_OCL_GetSupportedFeatures() { uint64_t capability = GTPIN_SUPPORTED_CAPABILITY::GTPIN_SUPPORTS_GRF_INFO | GTPIN_SUPPORTED_CAPABILITY::GTPIN_SUPPORTS_RERA; return capability; } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/gtpin_igc_ocl.h000066400000000000000000000121531363533017100256010ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "../../../Compiler/CodeGenPublic.h" #ifndef GTPIN_IGC_OCL_H #define GTPIN_IGC_OCL_H #if defined( _WIN32 ) || defined( _WIN64 ) // Windows #define MY_EXTERN_C extern "C" #define MY_DLLEXPORT __declspec( dllexport) __declspec( noinline ) #define MY_CALLINGSTD _fastcall #define MY_CDECL _cdecl #elif defined(ANDROID) || defined (__linux__) // Linux, Android #define MY_EXTERN_C extern "C" #define MY_DLLEXPORT __attribute__((visibility("default"))) #define MY_CALLINGSTD #define MY_CDECL #else #define MY_EXTERN_C extern "C" #define MY_DLLEXPORT #define MY_CALLINGSTD #define MY_CDECL #endif #ifndef GTPIN_EXTERNAL_TYPEDEFS_H // The following definitions must match those defined in gtpin_external_typedefs.h in the GT-Pin source tree #define GTPIN_EXTERNAL_TYPEDEFS_H typedef enum { GEN_ISA_TYPE_INVALID =0, GEN_ISA_TYPE_GEN6 = 1, GEN_ISA_TYPE_GEN7 = 2, GEN_ISA_TYPE_GEN7p5 = 3, GEN_ISA_TYPE_GEN8 = 4, GEN_ISA_TYPE_GEN9 = 5, GEN_ISA_TYPE_GEN10 = 6, GEN_ISA_TYPE_GEN11 = 7 } GEN_ISA_TYPE; typedef enum { GEN_GT_TYPE_INVALID = 0, GEN_GT_TYPE_GT1 = 1, GEN_GT_TYPE_GT2 = 2, GEN_GT_TYPE_GT3 = 3, GEN_GT_TYPE_GT4 = 4, GEN_GT_TYPE_GTVLV = 5, GEN_GT_TYPE_GTVLVPLUS = 6 } GEN_GT_TYPE; // List of driver versions that have GT-Pin support #define GTPIN_DRIVERVERSION_OPEN "intel-open" typedef enum { GTPIN_INVOKE_STRUCT_ARG_POS_FUNPTR = 0, GTPIN_INVOKE_STRUCT_ARG_POS_GTPROGRAMBINARY = 1, GTPIN_INVOKE_STRUCT_ARG_POS_OCLKERNELINFO = 2, GTPIN_INVOKE_STRUCT_ARG_POS_DRIVERVERSION = 3, GTPIN_INVOKE_STRUCT_ARG_POS_OCLDEBUGDATA=4, GTPIN_INVOKE_STRUCT_ARG_POS_OCLDEBUGSIZE=5, GTPIN_INVOKE_STRUCT_ARG_POS_LAST } GTPIN_INVOKE_STRUCT_ARG_POS; // This enum will be used as a bitmask so each member should // have a single bit set to 1. typedef enum { GTPIN_SUPPORTS_RERA = 0x1, GTPIN_SUPPORTS_GRF_INFO = 0x2, } GTPIN_SUPPORTED_CAPABILITY; typedef struct GTPIN_INVOKE_STRUCT { int _numArgs; void** _args; bool operator==( struct GTPIN_INVOKE_STRUCT& other ); } GTPIN_INVOKE_STRUCT; typedef bool (MY_CDECL *INVOKE_GTPIN_PROC)( GEN_ISA_TYPE isa, void* ptrToOrigGenBinary, int origGenBinarySizeInBytes, const char* commandLine, GTPIN_INVOKE_STRUCT* gtpinInvokeStruct, const int tbufIdx, const int sbufIdx, const int scacheIdx, void* &ptrToInstrumentedBinary, int& instrumentedGenBinarySizeInBytes, char*& resultMsg ); #endif // GTPIN_EXTERNAL_TYPEDEFS_H MY_EXTERN_C MY_DLLEXPORT bool MY_CALLINGSTD GTPIN_IGC_OCL_IsEnabled(); MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_NumberOfSurfaces(); MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_UpdateKernelInfo( const unsigned kernelBinarySize, const int scratchSurfBti, const int pBufBti ); MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_GetSurfaceBTI( const int i ); MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_GetEnqueueInstanceKernelArgNo(); MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_GetSurfaceKernelArgNo( const int i ); MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_CompilerReservedRegs( const char* regNames ); MY_EXTERN_C MY_DLLEXPORT char* MY_CALLINGSTD GTPIN_IGC_OCL_GetCommandLine(); MY_EXTERN_C MY_DLLEXPORT GTPIN_INVOKE_STRUCT* MY_CALLINGSTD GTPIN_IGC_OCL_GetInvokeStruct(); MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_FillAllKernelsInfo(); MY_EXTERN_C MY_DLLEXPORT GEN_ISA_TYPE MY_CALLINGSTD GTPIN_IGC_OCL_GetGenIsaFromPlatform( PLATFORM platform ); MY_EXTERN_C MY_DLLEXPORT int MY_CALLINGSTD GTPIN_IGC_OCL_Instrument( const GEN_ISA_TYPE genIsa, const char* driverVersionStr, const int originalBinarySize, void* originalBinaryOutput, int &instrumentedBinarySize, void* &instrumentedBinaryOutput); MY_EXTERN_C MY_DLLEXPORT uint64_t MY_CALLINGSTD GTPIN_IGC_OCL_GetSupportedFeatures(); #endif /* GTPIN_IGC_OCL_H */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/sp_convert_g8.h000066400000000000000000000713601363533017100255660ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "inc/common/Compiler/API/SurfaceFormats.h" #include "../Platform/cmd_media_enum_g8.h" #include "../Platform/cmd_shared_enum_g8.h" #include "patch_list.h" #include "../CommandStream/SamplerTypes.h" #include "../CommandStream/SurfaceTypes.h" namespace iOpenCL { /*****************************************************************************\ CONST: g_cConvertSamplerTextureAddressMode \*****************************************************************************/ static const G6HWC::GFXSHAREDSTATE_TEXCOORDMODE g_cConvertSamplerTextureAddressMode[] = { G6HWC::GFXSHAREDSTATE_TEXCOORDMODE_WRAP, // SAMPLER_TEXTURE_ADDRESS_MODE_WRAP G6HWC::GFXSHAREDSTATE_TEXCOORDMODE_MIRROR, // SAMPLER_TEXTURE_ADDRESS_MODE_MIRROR G6HWC::GFXSHAREDSTATE_TEXCOORDMODE_CLAMP, // SAMPLER_TEXTURE_ADDRESS_MODE_CLAMP G6HWC::GFXSHAREDSTATE_TEXCOORDMODE_CLAMP_BORDER, // SAMPLER_TEXTURE_ADDRESS_MODE_BORDER G6HWC::GFXSHAREDSTATE_TEXCOORDMODE_MIRROR_ONCE, // SAMPLER_TEXTURE_ADDRESS_MODE_MIRRORONCE G6HWC::GFXSHAREDSTATE_TEXCOORDMODE_MIRROR_101 // SAMPLER_TEXTURE_ADDRESS_MODE_MIRROR101 }; static_assert(sizeof(g_cConvertSamplerTextureAddressMode) == sizeof(G6HWC::GFXSHAREDSTATE_TEXCOORDMODE) * NUM_SAMPLER_TEXTURE_ADDRESS_MODES); /*****************************************************************************\ CONST: g_cConvertSamplerMapFilter \*****************************************************************************/ static const G6HWC::GFXSHAREDSTATE_MAPFILTER g_cConvertSamplerMapFilter[] = { G6HWC::GFXSHAREDSTATE_MAPFILTER_NEAREST, // SAMPLER_MAPFILTER_POINT G6HWC::GFXSHAREDSTATE_MAPFILTER_LINEAR, // SAMPLER_MAPFILTER_LINEAR G6HWC::GFXSHAREDSTATE_MAPFILTER_ANISOTROPIC, // SAMPLER_MAPFILTER_ANISOTROPIC G6HWC::GFXSHAREDSTATE_MAPFILTER_NEAREST, // SAMPLER_MAPFILTER_GAUSSIANQUAD G6HWC::GFXSHAREDSTATE_MAPFILTER_NEAREST, // SAMPLER_MAPFILTER_PYRAMIDALQUAD G6HWC::GFXSHAREDSTATE_MAPFILTER_MONO // SAMPLER_MAPFILTER_MONO }; static_assert(sizeof(g_cConvertSamplerMapFilter) == sizeof(G6HWC::GFXSHAREDSTATE_MAPFILTER) * NUM_SAMPLER_MAPFILTER_TYPES); /*****************************************************************************\ CONST: g_cConvertSamplerMipFilter \*****************************************************************************/ static const G6HWC::GFXSHAREDSTATE_MIPFILTER g_cConvertSamplerMipFilter[] = { G6HWC::GFXSHAREDSTATE_MIPFILTER_NEAREST, // SAMPLER_MIPFILTER_POINT G6HWC::GFXSHAREDSTATE_MIPFILTER_LINEAR, // SAMPLER_MIPFILTER_LINEAR G6HWC::GFXSHAREDSTATE_MIPFILTER_NONE // SAMPLER_MIPFILTER_NONE }; static_assert(sizeof(g_cConvertSamplerMipFilter) == sizeof(G6HWC::GFXSHAREDSTATE_MAPFILTER) * NUM_SAMPLER_MIPFILTER_TYPES); /*****************************************************************************\ CONST: g_cConvertCompareFunc \*****************************************************************************/ static const G6HWC::GFXSHAREDSTATE_PREFILTER_OPERATION g_cConvertCompareFunc[] = { G6HWC::GFXSHAREDSTATE_PREFILTER_NEVER, // SAMPLER_COMPARE_FUNC_ALWAYS G6HWC::GFXSHAREDSTATE_PREFILTER_ALWAYS, // SAMPLER_COMPARE_FUNC_NEVER G6HWC::GFXSHAREDSTATE_PREFILTER_LEQUAL, // SAMPLER_COMPARE_FUNC_LESS G6HWC::GFXSHAREDSTATE_PREFILTER_NOTEQUAL, // SAMPLER_COMPARE_FUNC_EQUAL G6HWC::GFXSHAREDSTATE_PREFILTER_LESS, // SAMPLER_COMPARE_FUNC_LESS_EQUAL G6HWC::GFXSHAREDSTATE_PREFILTER_GEQUAL, // SAMPLER_COMPARE_FUNC_GREATER G6HWC::GFXSHAREDSTATE_PREFILTER_EQUAL, // SAMPLER_COMPARE_FUNC_NOT_EQUAL G6HWC::GFXSHAREDSTATE_PREFILTER_GREATER // SAMPLER_COMPARE_FUNC_GREATER_EQUAL }; static_assert(sizeof(g_cConvertCompareFunc) == sizeof(G6HWC::GFXSHAREDSTATE_PREFILTER_OPERATION) * NUM_SAMPLER_COMPARE_FUNC_TYPES); /*****************************************************************************\ CONST: g_cConvertSurfaceFormat \*****************************************************************************/ static const G6HWC::GFXSHAREDSTATE_SURFACEFORMAT g_cConvertSurfaceFormat[] = { (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_UNKNOWN G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R64G64B64A64_FLOAT, // IGC::SURFACE_FORMAT_R64G64B64A64_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R64G64B64_FLOAT, // IGC::SURFACE_FORMAT_R64G64B64_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R64G64_FLOAT, // IGC::SURFACE_FORMAT_R64G64_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R64_FLOAT, // IGC::SURFACE_FORMAT_R64_FLOAT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R64G64B64A64_PASSTHRU (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R64G64B64_PASSTHRU (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R64G64_PASSTHRU (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R64_PASSTHRU G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_FLOAT, // IGC::SURFACE_FORMAT_R32G32B32A32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_SINT, // IGC::SURFACE_FORMAT_R32G32B32A32_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_UINT, // IGC::SURFACE_FORMAT_R32G32B32A32_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_UNORM, // IGC::SURFACE_FORMAT_R32G32B32A32_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_SNORM, // IGC::SURFACE_FORMAT_R32G32B32A32_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_USCALED, // IGC::SURFACE_FORMAT_R32G32B32A32_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32A32_SSCALED, // IGC::SURFACE_FORMAT_R32G32B32A32_SSCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R32G32B32A32_SFIXED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32X32_FLOAT, // IGC::SURFACE_FORMAT_R32G32B32X32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_FLOAT, // IGC::SURFACE_FORMAT_R32G32B32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_SINT, // IGC::SURFACE_FORMAT_R32G32B32_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_UINT, // IGC::SURFACE_FORMAT_R32G32B32_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_UNORM, // IGC::SURFACE_FORMAT_R32G32B32_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_SNORM, // IGC::SURFACE_FORMAT_R32G32B32_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_USCALED, // IGC::SURFACE_FORMAT_R32G32B32_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32B32_SSCALED, // IGC::SURFACE_FORMAT_R32G32B32_SSCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R32G32B32_SFIXED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32_FLOAT, // IGC::SURFACE_FORMAT_R32G32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32_SINT, // IGC::SURFACE_FORMAT_R32G32_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32_UINT, // IGC::SURFACE_FORMAT_R32G32_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32_UNORM, // IGC::SURFACE_FORMAT_R32G32_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32_SNORM, // IGC::SURFACE_FORMAT_R32G32_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32_USCALED, // IGC::SURFACE_FORMAT_R32G32_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32G32_SSCALED, // IGC::SURFACE_FORMAT_R32G32_SSCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R32G32_SFIXED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32_FLOAT, // IGC::SURFACE_FORMAT_R32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32_SINT, // IGC::SURFACE_FORMAT_R32_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32_UINT, // IGC::SURFACE_FORMAT_R32_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32_UNORM, // IGC::SURFACE_FORMAT_R32_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32_SNORM, // IGC::SURFACE_FORMAT_R32_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32_USCALED, // IGC::SURFACE_FORMAT_R32_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32_SSCALED, // IGC::SURFACE_FORMAT_R32_SSCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R32_SFIXED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS, // IGC::SURFACE_FORMAT_R32_FLOAT_X8X24_TYPELESS (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R32_FLOAT_S8_UINT_X24_TYPELESS G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_X32_TYPELESS_G8X24_UINT, // IGC::SURFACE_FORMAT_X32_TYPELESS_G8X24_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R24_UNORM_X8_TYPELESS, // IGC::SURFACE_FORMAT_R24_UNORM_X8_TYPELESS (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R24_UNORM_S8_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_X24_TYPELESS_G8_UINT, // IGC::SURFACE_FORMAT_X24_TYPELESS_G8_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_FLOAT, // IGC::SURFACE_FORMAT_R16G16B16A16_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_SINT, // IGC::SURFACE_FORMAT_R16G16B16A16_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_UINT, // IGC::SURFACE_FORMAT_R16G16B16A16_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_UNORM, // IGC::SURFACE_FORMAT_R16G16B16A16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_SNORM, // IGC::SURFACE_FORMAT_R16G16B16A16_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_USCALED, // IGC::SURFACE_FORMAT_R16G16B16A16_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16A16_SSCALED, // IGC::SURFACE_FORMAT_R16G16B16A16_SSCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16X16_UNORM, // IGC::SURFACE_FORMAT_R16G16B16X16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16X16_FLOAT, // IGC::SURFACE_FORMAT_R16G16B16X16_FLOAT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R16G16B16_SINT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R16G16B16_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16_UNORM, // IGC::SURFACE_FORMAT_R16G16B16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16_SNORM, // IGC::SURFACE_FORMAT_R16G16B16_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16_USCALED, // IGC::SURFACE_FORMAT_R16G16B16_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16B16_SSCALED, // IGC::SURFACE_FORMAT_R16G16B16_SSCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R16G16B16_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16_FLOAT, // IGC::SURFACE_FORMAT_R16G16_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16_SINT, // IGC::SURFACE_FORMAT_R16G16_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16_UINT, // IGC::SURFACE_FORMAT_R16G16_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16_UNORM, // IGC::SURFACE_FORMAT_R16G16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16_SNORM, // IGC::SURFACE_FORMAT_R16G16_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16_USCALED, // IGC::SURFACE_FORMAT_R16G16_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16G16_SSCALED, // IGC::SURFACE_FORMAT_R16G16_SSCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16_FLOAT, // IGC::SURFACE_FORMAT_R16_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16_SINT, // IGC::SURFACE_FORMAT_R16_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16_UINT, // IGC::SURFACE_FORMAT_R16_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16_UNORM, // IGC::SURFACE_FORMAT_R16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16_SNORM, // IGC::SURFACE_FORMAT_R16_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16_USCALED, // IGC::SURFACE_FORMAT_R16_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R16_SSCALED, // IGC::SURFACE_FORMAT_R16_SSCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R11G11B10_FLOAT, // IGC::SURFACE_FORMAT_R11G11B10_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10A2_UNORM, // IGC::SURFACE_FORMAT_R10G10B10A2_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10A2_UNORM_SRGB, // IGC::SURFACE_FORMAT_R10G10B10A2_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10A2_UINT, // IGC::SURFACE_FORMAT_R10G10B10A2_UINT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R10G10B10A2_SNORM (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R10G10B10A2_USCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R10G10B10A2_SSCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R10G10B10A2_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM, // IGC::SURFACE_FORMAT_R10G10B10_SNORM_A2_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R10G10B10X2_USCALED, // IGC::SURFACE_FORMAT_R10G10B10X2_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B10G10R10A2_UNORM, // IGC::SURFACE_FORMAT_B10G10R10A2_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B10G10R10A2_UNORM_SRGB, // IGC::SURFACE_FORMAT_B10G10R10A2_UNORM_SRGB (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_B10G10R10A2_UINT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_B10G10R10A2_SNORM (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_B10G10R10A2_USCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_B10G10R10A2_SSCALED (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_B10G10R10A2_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B10G10R10X2_UNORM, // IGC::SURFACE_FORMAT_B10G10R10X2_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R9G9B9E5_SHAREDEXP, // IGC::SURFACE_FORMAT_R9G9B9E5_SHAREDEXP G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_SINT, // IGC::SURFACE_FORMAT_R8G8B8A8_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UINT, // IGC::SURFACE_FORMAT_R8G8B8A8_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UNORM, // IGC::SURFACE_FORMAT_R8G8B8A8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_UNORM_SRGB, // IGC::SURFACE_FORMAT_R8G8B8A8_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_SNORM, // IGC::SURFACE_FORMAT_R8G8B8A8_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_USCALED, // IGC::SURFACE_FORMAT_R8G8B8A8_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8A8_SSCALED, // IGC::SURFACE_FORMAT_R8G8B8A8_SSCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8X8_UNORM, // IGC::SURFACE_FORMAT_R8G8B8X8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8X8_UNORM_SRGB, // IGC::SURFACE_FORMAT_R8G8B8X8_UNORM_SRGB (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R8G8_SNORM_B8X8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B8G8R8A8_UNORM, // IGC::SURFACE_FORMAT_B8G8R8A8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB, // IGC::SURFACE_FORMAT_B8G8R8A8_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B8G8R8X8_UNORM, // IGC::SURFACE_FORMAT_B8G8R8X8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B8G8R8X8_UNORM_SRGB, // IGC::SURFACE_FORMAT_B8G8R8X8_UNORM_SRGB (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R8G8B8_SINT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R8G8B8_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_UNORM, // IGC::SURFACE_FORMAT_R8G8B8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_SNORM, // IGC::SURFACE_FORMAT_R8G8B8_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_USCALED, // IGC::SURFACE_FORMAT_R8G8B8_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8B8_SSCALED, // IGC::SURFACE_FORMAT_R8G8B8_SSCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8_SINT, // IGC::SURFACE_FORMAT_R8G8_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8_UINT, // IGC::SURFACE_FORMAT_R8G8_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8_UNORM, // IGC::SURFACE_FORMAT_R8G8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8_SNORM, // IGC::SURFACE_FORMAT_R8G8_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8_USCALED, // IGC::SURFACE_FORMAT_R8G8_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8_SSCALED, // IGC::SURFACE_FORMAT_R8G8_SSCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_SINT, // IGC::SURFACE_FORMAT_R8_SINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_UINT, // IGC::SURFACE_FORMAT_R8_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_UNORM, // IGC::SURFACE_FORMAT_R8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_SNORM, // IGC::SURFACE_FORMAT_R8_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_USCALED, // IGC::SURFACE_FORMAT_R8_USCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_SSCALED, // IGC::SURFACE_FORMAT_R8_SSCALED G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B5G6R5_UNORM, // IGC::SURFACE_FORMAT_B5G6R5_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B5G6R5_UNORM_SRGB, // IGC::SURFACE_FORMAT_B5G6R5_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B5G5R5A1_UNORM, // IGC::SURFACE_FORMAT_B5G5R5A1_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B5G5R5A1_UNORM_SRGB, // IGC::SURFACE_FORMAT_B5G5R5A1_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B5G5R5X1_UNORM, // IGC::SURFACE_FORMAT_B5G5R5X1_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B5G5R5X1_UNORM_SRGB, // IGC::SURFACE_FORMAT_B5G5R5X1_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R5G5_SNORM_B6_UNORM, // IGC::SURFACE_FORMAT_R5G5_SNORM_B6_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B4G4R4A4_UNORM, // IGC::SURFACE_FORMAT_B4G4R4A4_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_B4G4R4A4_UNORM_SRGB, // IGC::SURFACE_FORMAT_B4G4R4A4_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R1_UINT, // IGC::SURFACE_FORMAT_R1_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R1_UINT, // IGC::SURFACE_FORMAT_R1_UINT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_I32X32_FLOAT, // IGC::SURFACE_FORMAT_I32X32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L32A32_FLOAT, // IGC::SURFACE_FORMAT_L32A32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L32X32_FLOAT, // IGC::SURFACE_FORMAT_L32X32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_A32X32_FLOAT, // IGC::SURFACE_FORMAT_A32X32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_I24X8_UNORM, // IGC::SURFACE_FORMAT_I24X8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L24X8_UNORM, // IGC::SURFACE_FORMAT_L24X8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_A24X8_UNORM, // IGC::SURFACE_FORMAT_A24X8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_I32_FLOAT, // IGC::SURFACE_FORMAT_I32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L32_FLOAT, // IGC::SURFACE_FORMAT_L32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_A32_FLOAT, // IGC::SURFACE_FORMAT_A32_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L16A16_FLOAT, // IGC::SURFACE_FORMAT_L16A16_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L16A16_UNORM, // IGC::SURFACE_FORMAT_L16A16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_I16_FLOAT, // IGC::SURFACE_FORMAT_I16_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_I16_UNORM, // IGC::SURFACE_FORMAT_I16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L16_FLOAT, // IGC::SURFACE_FORMAT_L16_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L16_UNORM, // IGC::SURFACE_FORMAT_L16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_A16_FLOAT, // IGC::SURFACE_FORMAT_A16_FLOAT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_A16_UNORM, // IGC::SURFACE_FORMAT_A16_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L8A8_UNORM, // IGC::SURFACE_FORMAT_L8A8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L8A8_UNORM_SRGB, // IGC::SURFACE_FORMAT_L8A8_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_I8_UNORM, // IGC::SURFACE_FORMAT_I8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L8_UNORM, // IGC::SURFACE_FORMAT_L8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_L8_UNORM_SRGB, // IGC::SURFACE_FORMAT_L8_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_A8_UNORM, // IGC::SURFACE_FORMAT_A8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_P4A4_UNORM, // IGC::SURFACE_FORMAT_P4A4_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_A4P4_UNORM, // IGC::SURFACE_FORMAT_A4P4_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_P8_UNORM, // IGC::SURFACE_FORMAT_P8_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_P2_UNORM, // IGC::SURFACE_FORMAT_P2_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC1_UNORM, // IGC::SURFACE_FORMAT_BC1_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC2_UNORM, // IGC::SURFACE_FORMAT_BC2_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC3_UNORM, // IGC::SURFACE_FORMAT_BC3_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC4_UNORM, // IGC::SURFACE_FORMAT_BC4_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC5_UNORM, // IGC::SURFACE_FORMAT_BC5_UNORM (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_BC7_UNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC1_UNORM_SRGB, // IGC::SURFACE_FORMAT_BC1_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC2_UNORM_SRGB, // IGC::SURFACE_FORMAT_BC2_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC3_UNORM_SRGB, // IGC::SURFACE_FORMAT_BC3_UNORM_SRGB (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_BC7_UNORM_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC4_SNORM, // IGC::SURFACE_FORMAT_BC4_SNORM G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_BC5_SNORM, // IGC::SURFACE_FORMAT_BC5_SNORM (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_BC6H_UF16 (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_BC6H_SF16 G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_DXT1_RGB, // IGC::SURFACE_FORMAT_DXT1_RGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_DXT1_RGB_SRGB, // IGC::SURFACE_FORMAT_DXT1_RGB_SRGB G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_FXT1, // IGC::SURFACE_FORMAT_FXT1 G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_YCRCB_NORMAL, // IGC::SURFACE_FORMAT_YCRCB_NORMAL G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_YCRCB_SWAPUVY, // IGC::SURFACE_FORMAT_YCRCB_SWAPUVY G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_YCRCB_SWAPUV, // IGC::SURFACE_FORMAT_YCRCB_SWAPUV G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_YCRCB_SWAPY, // IGC::SURFACE_FORMAT_YCRCB_SWAPY G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_UNORM, // IGC::SURFACE_FORMAT_PLANAR_Y G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_UNORM, // IGC::SURFACE_FORMAT_PLANAR_U G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8_UNORM, // IGC::SURFACE_FORMAT_PLANAR_V G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_R8G8_UNORM, // IGC::SURFACE_FORMAT_PLANAR_UV (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R16G16B16_SINT_OGL_VIRT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R16G16B16_UINT_OGL_VIRT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R8G8B8_SINT_OGL_VIRT (G6HWC::GFXSHAREDSTATE_SURFACEFORMAT)0x0FF, // IGC::SURFACE_FORMAT_R8G8B8_UINT_OGL_VIRT G6HWC::GFXSHAREDSTATE_SURFACEFORMAT_RAW, // IGC::SURFACE_FORMAT_RAW }; static_assert(sizeof(g_cConvertSurfaceFormat) == sizeof(G6HWC::GFXSHAREDSTATE_SURFACEFORMAT) * IGC::NUM_SURFACE_FORMATS); /*****************************************************************************\ CONST: g_cConvertSurfaceMipMapLayout \*****************************************************************************/ static const G6HWC::GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT g_cConvertSurfaceMipMapLayout[] = { G6HWC::GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT_BELOW, // RESOURCE_MIPMAP_LAYOUT_BELOW G6HWC::GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT_RIGHT, // RESOURCE_MIPMAP_LAYOUT_RIGHT }; static_assert(sizeof(g_cConvertSurfaceMipMapLayout) == sizeof(G6HWC::GFXSHAREDSTATE_SURFACE_MIPMAPLAYOUT) * NUM_RESOURCE_MIPMAP_LAYOUT_MODES); /*****************************************************************************\ CONST: g_cConvertSurfaceType \*****************************************************************************/ static const G6HWC::GFXSHAREDSTATE_SURFACETYPE g_cConvertSurfaceType[] = { G6HWC::GFXSHAREDSTATE_SURFACETYPE_NULL, // SURFACE_UNKNOWN G6HWC::GFXSHAREDSTATE_SURFACETYPE_NULL, // SURFACE_NULL G6HWC::GFXSHAREDSTATE_SURFACETYPE_1D, // SURFACE_1D G6HWC::GFXSHAREDSTATE_SURFACETYPE_1D, // SURFACE_1D_ARRAY G6HWC::GFXSHAREDSTATE_SURFACETYPE_2D, // SURFACE_2D G6HWC::GFXSHAREDSTATE_SURFACETYPE_2D, // SURFACE_2D_ARRAY G6HWC::GFXSHAREDSTATE_SURFACETYPE_3D, // SURFACE_3D G6HWC::GFXSHAREDSTATE_SURFACETYPE_CUBE, // SURFACE_CUBE G6HWC::GFXSHAREDSTATE_SURFACETYPE_CUBE, // SURFACE_CUBE_ARRAY G6HWC::GFXSHAREDSTATE_SURFACETYPE_BUFFER, // SURFACE_CONSTANT G6HWC::GFXSHAREDSTATE_SURFACETYPE_BUFFER, // SURFACE_BUFFER G6HWC::GFXSHAREDSTATE_SURFACETYPE_2D, // SURFACE_2D_MEDIA G6HWC::GFXSHAREDSTATE_SURFACETYPE_2D // SURFACE_2D_MEDIA_BLOCK }; static_assert(sizeof(g_cConvertSurfaceType) == sizeof(G6HWC::GFXSHAREDSTATE_SURFACETYPE) * NUM_SURFACE_TYPES); #if 0 /*****************************************************************************\ CONST: g_cConvertResourceType \*****************************************************************************/ static const iOpenCL::IMAGE_MEMORY_OBJECT_TYPE g_cConvertResourceType[] = { iOpenCL::IMAGE_MEMORY_OBJECT_INVALID, // SHADER_RESOURCE_INVALID iOpenCL::IMAGE_MEMORY_OBJECT_BUFFER, // SHADER_RESOURCE_BUFFER iOpenCL::IMAGE_MEMORY_OBJECT_1D, // SHADER_RESOURCE_1D iOpenCL::IMAGE_MEMORY_OBJECT_1D_ARRAY, // SHADER_RESOURCE_1D_ARRAY iOpenCL::IMAGE_MEMORY_OBJECT_2D, // SHADER_RESOURCE_2D iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY, // SHADER_RESOURCE_2D_ARRAY iOpenCL::IMAGE_MEMORY_OBJECT_3D, // SHADER_RESOURCE_3D iOpenCL::IMAGE_MEMORY_OBJECT_CUBE, // SHADER_RESOURCE_CUBE iOpenCL::IMAGE_MEMORY_OBJECT_CUBE_ARRAY,// SHADER_RESOURCE_CUBE_ARRAY iOpenCL::IMAGE_MEMORY_OBJECT_2D_MEDIA, // SHADER_RESOURCE_2D_MEDIA }; static_assert(sizeof(g_cConvertResourceType) == sizeof(iOpenCL::IMAGE_MEMORY_OBJECT_TYPE) * USC::NUM_SHADER_RESOURCE_TYPES); #endif } // namespace iOpenCL intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/sp_debug.cpp000066400000000000000000000052061363533017100251250ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include #include #include #if defined(_WIN32) #include #endif #include #include "IGC/common/igc_regkeys.hpp" #include "sp_debug.h" namespace iOpenCL { void __cdecl DebugMessageStr(std::string& output, unsigned int ulDebugLevel, const char* fmt, ...) { //if( str && ( ( g_DebugControl.MsgLevel & ulDebugLevel ) != GFXDBG_OFF ) ) { va_list args; va_start(args, fmt); #if defined(ICBE_LHDM) || defined(_WIN32) if (IGC_IS_FLAG_ENABLED(DumpPatchTokens)) { const size_t length = _vscprintf(fmt, args); char* temp = new char[length + 1]; if (temp) { vsprintf_s(temp, length + 1, fmt, args); //This prints the output string to the console. We don't want that in release internal mode OutputDebugStringA("INTC CBE: "); OutputDebugStringA(temp); output += temp; delete[] temp; } } #else if (IGC_IS_FLAG_ENABLED(DumpPatchTokens)) { va_list argcopy; va_copy(argcopy, args); const size_t length = vsnprintf(NULL, 0, fmt, argcopy); char* temp = new char[length + 1]; if (temp) { vsnprintf(temp, length + 1, fmt, args); output += temp; delete[] temp; } } #endif va_end(args); } } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/sp_debug.h000066400000000000000000000042271363533017100245740ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #include "IGC/common/igc_debug.h" namespace iOpenCL { /*****************************************************************************\ Function: DebugMessage \*****************************************************************************/ void DebugMessageStr(std::string& output, unsigned int ulDebugLevel, const char* fmt, ...); /*****************************************************************************\ MACRO: ICBE_DPF_STR \*****************************************************************************/ #ifndef ICBE_DPF_STR #if defined(_DEBUG) || defined(_INTERNAL) || defined(_RELEASE_INTERNAL) #define ICBE_DPF_STR iOpenCL::DebugMessageStr #else #if defined(ICBE_LHDM) || defined(_WIN32) #define ICBE_DPF_STR(output, format, args, ...) #else #define ICBE_DPF_STR(output, format, args...) #endif #endif // _DEBUG #endif // ICBE_DPF_STR } // namespace iOpenCL intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/sp_g8.cpp000066400000000000000000002742671363533017100243740ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "common/LLVMWarningsPush.hpp" #include #include "common/LLVMWarningsPop.hpp" #include "sp_g8.h" #include "sp_convert_g8.h" #include "sp_debug.h" #include "../util/BinaryStream.h" #include "../Platform/cmd_shared_init_g8.h" #include "../Platform/cmd_media_init_g8.h" #include "../Platform/cmd_parser_g8.h" #include "common/allocator.h" #include "common/igc_regkeys.hpp" #include "common/Stats.hpp" #include "common/SystemThread.h" #include "common/secure_mem.h" #include "common/debug/Dump.hpp" #include "common/debug/Debug.hpp" #include #include "patch_list.h" #include "program_debug_data.h" #include "patch_shared.h" #include "patch_g7.h" #include "patch_g8.h" #include "../../../Compiler/CodeGenPublic.h" #include "../../../visa/include/visaBuilder_interface.h" #include "gtpin_igc_ocl.h" #include #include #include "Probe.h" using namespace IGC; using namespace IGC::IGCMD; using namespace IGC::Debug; namespace iOpenCL { __forceinline long FloatToLong( const float value ) { #if defined(_WIN32) && defined(_MSC_VER) return _mm_cvtsi128_si32( _mm_cvttps_epi32( _mm_set_ps1( value ) ) ); #else return (long)value; #endif } template __forceinline Type GetAlignmentOffset( const Type size, const size_t alignSize ) { IGC_ASSERT(alignSize); Type typedAlignSize = (Type)alignSize; return (typedAlignSize - (size % typedAlignSize)) % typedAlignSize; } template __forceinline Type FloatToFixed( float value, const int whole, const int fractional, const int round = 0 ) { IGC_ASSERT(fractional + whole <= 32); // Optional floating point rounding precision value += ( round != 0 ) ? 0.5f * ( 1.0f / (float)( 1 << round ) ) : 0; Type fixed = (Type)FloatToLong( value * (float)( 1 << fractional ) ); DWORD mask = 0xffffffff << ( whole + fractional ); IGC_ASSERT( (( fixed >= 0 ) && (( fixed & mask ) == 0 )) || (( fixed < 0 ) && (( fixed & mask ) == mask ))); return fixed; } #define HASH_JENKINS_MIX(a,b,c) \ { \ a -= b; a -= c; a ^= (c>>13); \ b -= c; b -= a; b ^= (a<<8); \ c -= a; c -= b; c ^= (b>>13); \ a -= b; a -= c; a ^= (c>>12); \ b -= c; b -= a; b ^= (a<<16); \ c -= a; c -= b; c ^= (b>>5); \ a -= b; a -= c; a ^= (c>>3); \ b -= c; b -= a; b ^= (a<<10); \ c -= a; c -= b; c ^= (b>>15); \ } inline QWORD Hash( const DWORD *data, DWORD count ) { DWORD a = 0x428a2f98, hi = 0x71374491, lo = 0xb5c0fbcf; while( count-- ) { a ^= *(data++); // printf("%8x, %8x, %8x, %8x\n", a ,hi, lo, *data); HASH_JENKINS_MIX( a, hi, lo ); } return (((QWORD)hi)<<32)|lo; } #undef HASH_JENKINS_MIX template< typename Type > __forceinline bool IsAligned( Type size, const size_t alignSize ) { return ( ( size % alignSize ) == 0 ); } RETVAL g_cInitRetValue = { 1 }; static const int numAllowedAttributes = 4; const char* allowedAttributes[numAllowedAttributes] = { "reqd_sub_group_size", "reqd_work_group_size", "vec_type_hint", "work_group_size_hint", }; /*****************************************************************************\ STRUCT: SStateProcessorContextGen8_0 \*****************************************************************************/ struct SStateProcessorContextGen8_0 { struct _Runtime { // CS_URB_STATE DWORD URBEntryAllocationSize; } Runtime; struct _Kernel { // System Kernel bool SystemKernelPresent; DWORD SystemKernelOffset; // Client Kernel DWORD KernelOffset; } Kernel; struct _Dynamic { // SAMPLER_BORDER_COLOR_STATE DWORD SamplerBorderColorStateOffset; // SAMPLER_STATE DWORD SamplerCount; DWORD SamplerArrayOffset; DWORD SamplerOffset[ G6HWC::g_cNumSamplersPerProgram ]; // INTERFACE_DESCRIPTOR DWORD InterfaceDescriptorDataOffset; // VFE_STATE DWORD VFEStateOffset; // CONSTANT_BUFFER DWORD ConstantBufferDataOffset; DWORD ConstantBufferDataLength; } Dynamic; struct _Static { // Scratch Space bool ScratchSpacePresent; DWORD ScratchSpaceOffset; } Static; struct _Surface { // BINDING_TABLE_STATE DWORD BindingTableOffset; // SURFACE_STATE DWORD SurfaceCount; DWORD SurfaceArrayOffset; DWORD SurfaceOffset[ G6HWC::g_cNumSurfacesPerProgram ]; } Surface; }; CGen8OpenCLStateProcessor::CGen8OpenCLStateProcessor(PLATFORM platform) : m_Platform(platform) { G6HWC::InitializeCapsGen8( &m_HWCaps ); } CGen8OpenCLStateProcessor::~CGen8OpenCLStateProcessor( ) { // Nothing } void CGen8OpenCLStateProcessor::CreateKernelBinary( const char* rawIsaBinary, unsigned int rawIsaBinarySize, const IGC::SOpenCLKernelInfo& annotations, const IGC::SOpenCLProgramInfo& programInfo, const IGC::CBTILayout& layout, Util::BinaryStream& kernelBinary, USC::SSystemThreadKernelOutput* pSystemThreadKernelOutput, unsigned int unpaddedBinarySize) { Util::BinaryStream kernelHeap; Util::BinaryStream surfaceStateHeap; Util::BinaryStream dynamicStateHeap; Util::BinaryStream generalStateHeap; Util::BinaryStream patchListHeap; SStateProcessorContextGen8_0 kernelContext = {}; RETVAL retValue = g_cInitRetValue; const bool gtpinEnabled = GTPIN_IGC_OCL_IsEnabled(); ICBE_DPF_STR(m_oclStateDebugMessagePrintOut, GFXDBG_HARDWARE, "\n"); ICBE_DPF_STR(m_oclStateDebugMessagePrintOut, GFXDBG_HARDWARE, "** Kernel Patch Lists : Kernel Name = %s **\n", annotations.m_kernelName.c_str()); ICBE_DPF_STR(m_oclStateDebugMessagePrintOut, GFXDBG_HARDWARE, "\n"); if( retValue.Success ) { retValue = CreateKernelHeap( annotations, rawIsaBinary, rawIsaBinarySize, pSystemThreadKernelOutput, kernelContext, kernelHeap ); } if( retValue.Success ) { retValue = CreateSurfaceStateHeap( annotations, layout, gtpinEnabled, kernelContext, surfaceStateHeap ); } if( retValue.Success ) { retValue = CreateDynamicStateHeap( annotations, kernelContext, dynamicStateHeap ); } if( retValue.Success ) { retValue = CreatePatchList( annotations, programInfo, layout, kernelContext, gtpinEnabled, patchListHeap ); } if( retValue.Success ) { retValue = CombineKernelBinary( kernelContext, annotations, kernelHeap, generalStateHeap, dynamicStateHeap, surfaceStateHeap, patchListHeap, unpaddedBinarySize, kernelBinary ); } if (IGC_IS_FLAG_ENABLED(EnableCosDump)) { auto name = DumpName(IGC::Debug::GetShaderOutputName()) .Hash(m_Context ? m_Context->hash : ShaderHash()) .Type(ShaderType::OPENCL_SHADER) .PostFix("kernel_" + annotations.m_kernelName + std::to_string( annotations.m_executionEnivronment.CompiledSIMDSize)) .Extension("cos"); Dump dump(name, DumpType::COS_TEXT); IGC::Debug::DumpLock(); dump.stream() << m_oclStateDebugMessagePrintOut; IGC::Debug::DumpUnlock(); m_oclStateDebugMessagePrintOut.clear(); } } void CGen8OpenCLStateProcessor::CreateProgramScopePatchStream(const IGC::SOpenCLProgramInfo& annotations, Util::BinaryStream& membuf) { RETVAL retValue = g_cInitRetValue; std::string &output = m_oclStateDebugMessagePrintOut; ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\n"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "** Program Scope patch lists **\n"); ICBE_DPF_STR(output, GFXDBG_HARDWARE, "\n"); for (auto &iter : annotations.m_initConstantAnnotation) { iOpenCL::SPatchAllocateConstantMemorySurfaceProgramBinaryInfo patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_PROGRAM_BINARY_INFO; patch.Size = sizeof( patch ); patch.ConstantBufferIndex = DEFAULT_CONSTANT_BUFFER_INDEX; patch.InlineDataSize = (DWORD)iter->InlineData.size(); retValue = AddPatchItem( patch, membuf ); // And now write the actual data membuf.Write((char*)iter->InlineData.data(), iter->InlineData.size()); } for (auto &iter : annotations.m_initGlobalAnnotation) { iOpenCL::SPatchAllocateGlobalMemorySurfaceProgramBinaryInfo patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_GLOBAL_MEMORY_SURFACE_PROGRAM_BINARY_INFO; patch.Size = sizeof( patch ); patch.Type = iOpenCL::GLOBAL_BUFFER_TYPE_INLINE; patch.GlobalBufferIndex = 0; patch.InlineDataSize = (DWORD)iter->InlineData.size(); retValue = AddPatchItem( patch, membuf ); // And now write the actual data membuf.Write((char*)iter->InlineData.data(), iter->InlineData.size()); } for (auto &iter : annotations.m_initKernelTypeAnnotation) { iOpenCL::SPatchKernelTypeProgramBinaryInfo patch; memset(&patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_CONSTRUCTOR_DESTRUCTOR_KERNEL_PROGRAM_BINARY_INFO; patch.Size = sizeof(patch); patch.Type = iter->Type; patch.InlineDataSize = iter->KernelName.size(); retValue = AddPatchItem( patch, membuf); // And now write the actual data membuf.Write((char*)iter->KernelName.data(), iter->KernelName.size()); } for (auto &iter : annotations.m_initGlobalPointerAnnotation) { iOpenCL::SPatchGlobalPointerProgramBinaryInfo patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_GLOBAL_POINTER_PROGRAM_BINARY_INFO; patch.Size = sizeof( patch ); patch.GlobalBufferIndex = iter->PointerBufferIndex; patch.GlobalPointerOffset = iter->PointerOffset; patch.BufferType = (iter->PointeeAddressSpace == IGC::ADDRESS_SPACE_GLOBAL) ? PROGRAM_SCOPE_GLOBAL_BUFFER : PROGRAM_SCOPE_CONSTANT_BUFFER; patch.BufferIndex = iter->PointeeBufferIndex; retValue = AddPatchItem( patch, membuf ); } for (auto &iter : annotations.m_initConstantPointerAnnotation) { iOpenCL::SPatchConstantPointerProgramBinaryInfo patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_CONSTANT_POINTER_PROGRAM_BINARY_INFO; patch.Size = sizeof( patch ); patch.ConstantBufferIndex = iter->PointerBufferIndex; patch.ConstantPointerOffset = iter->PointerOffset; patch.BufferType = (iter->PointeeAddressSpace == IGC::ADDRESS_SPACE_GLOBAL) ? PROGRAM_SCOPE_GLOBAL_BUFFER : PROGRAM_SCOPE_CONSTANT_BUFFER; patch.BufferIndex = iter->PointeeBufferIndex; retValue = AddPatchItem( patch, membuf ); } } void CGen8OpenCLStateProcessor::CreateKernelDebugData( const char* rawDebugDataVISA, unsigned int rawDebugDataVISASize, const char* rawDebugDataGenISA, unsigned int rawDebugDataGenISASize, const std::string& kernelName, Util::BinaryStream& kernelDebugData) { RETVAL retValue = g_cInitRetValue; Util::BinaryStream kernelVisaDbg; Util::BinaryStream kernelGenIsaDbg; // Source -> VISA debug info if( kernelVisaDbg.Write( rawDebugDataVISA, rawDebugDataVISASize ) == false ) { IGC_ASSERT(0); retValue.Success = false; } kernelVisaDbg.Align( sizeof( DWORD ) ); // VISA -> Gen ISA debug info if( kernelGenIsaDbg.Write( rawDebugDataGenISA, rawDebugDataGenISASize ) == false ) { IGC_ASSERT(0); retValue.Success = false; } kernelGenIsaDbg.Align( sizeof( DWORD ) ); if( retValue.Success ) { iOpenCL::SKernelDebugDataHeaderIGC header; memset( &header, 0, sizeof( header ) ); header.KernelNameSize = (uint32_t)kernelName.size() + 1; header.KernelNameSize += GetAlignmentOffset( header.KernelNameSize, sizeof(DWORD) ); header.SizeVisaDbgInBytes = (uint32_t)kernelVisaDbg.Size(); header.SizeGenIsaDbgInBytes = (uint32_t)kernelGenIsaDbg.Size(); kernelDebugData.Write( header ); kernelDebugData.Write( kernelName.c_str(), kernelName.size() + 1 ); kernelDebugData.Align( sizeof (DWORD ) ); kernelDebugData.Write( kernelVisaDbg ); kernelDebugData.Write( kernelGenIsaDbg ); IGC_ASSERT(IsAligned(kernelDebugData.Size(), sizeof(DWORD))); } } const G6HWC::SMediaHardwareCapabilities& CGen8OpenCLStateProcessor::HWCaps() const { return m_HWCaps; } /*****************************************************************************\ Function: CGen8StateProcessor::AddSystemKernel Description: Input: Output: RETVAL \*****************************************************************************/ RETVAL CGen8OpenCLStateProcessor::AddSystemKernel( const USC::SSystemThreadKernelOutput* pSystemThreadKernelOutput, SStateProcessorContextGen8_0& context, Util::BinaryStream& membuf) { RETVAL retValue = g_cInitRetValue; IGC_ASSERT(context.Kernel.SystemKernelPresent == false); context.Kernel.SystemKernelPresent = true; context.Kernel.SystemKernelOffset = (DWORD)membuf.Size(); // Add the system kernel. if (retValue.Success) { const void* pKernel = pSystemThreadKernelOutput->m_pKernelProgram; const DWORD size = pSystemThreadKernelOutput->m_KernelProgramSize; if (membuf.Write(static_cast(pKernel), size) == false) { IGC_ASSERT(0); retValue.Success = false; } membuf.AddPadding(HWCaps().InstructionCachePrefetchSize); membuf.Align(sizeof(DWORD)); } return retValue; } RETVAL CGen8OpenCLStateProcessor::CreateKernelHeap( const IGC::SOpenCLKernelInfo& annotations, const char* kernelBinary, unsigned int kernelBinarySize, USC::SSystemThreadKernelOutput* pSystemThreadKernelOutput, SStateProcessorContextGen8_0& context, Util::BinaryStream& membuf ) { RETVAL retValue = g_cInitRetValue; // Add the system kernel if required. if (m_Context) { const auto options = m_Context->m_InternalOptions; if (retValue.Success && (options.IncludeSIPCSR || options.IncludeSIPKernelDebug || options.IncludeSIPKernelDebugWithLocalMemory)) { retValue = AddSystemKernel( pSystemThreadKernelOutput, context, membuf); } } if (retValue.Success) { if (membuf.Write(kernelBinary, kernelBinarySize) == false) { IGC_ASSERT(0); retValue.Success = false; } membuf.AddPadding(HWCaps().InstructionCachePrefetchSize); membuf.Align(sizeof(DWORD)); } return retValue; } RETVAL CGen8OpenCLStateProcessor::CreateSurfaceStateHeap( const IGC::SOpenCLKernelInfo& annotations, const IGC::CBTILayout& layout, const bool gtpinEnabled, SStateProcessorContextGen8_0& context, Util::BinaryStream& membuf ) { struct SurfaceState { SURFACE_TYPE type; SURFACE_FORMAT surfaceFormat; DWORD bufferLength; bool isMultiSampleImage; SurfaceState(SURFACE_TYPE type, SURFACE_FORMAT surfaceFormat, DWORD bufferLength, bool isMultiSampleImage) : type(type), surfaceFormat(surfaceFormat), bufferLength(bufferLength), isMultiSampleImage(isMultiSampleImage) {} }; RETVAL retValue = g_cInitRetValue; // collect all the surface state entries in an ordered map keyed on the BTI. // Walking the map at the end will insert all the BTI entries in ascending order. std::map SurfaceStates; // First, System Thread Surface if (retValue.Success && m_Context && m_Context->m_InternalOptions.KernelDebugEnable) { unsigned int bti = layout.GetSystemThreadBindingTableIndex(); SurfaceStates.insert( std::make_pair( bti, SurfaceState( SURFACE_BUFFER, SURFACE_FORMAT_UNKNOWN, 0, false))); } // Now, add the constant buffer, if present. for( auto iter : annotations.m_pointerInput ) { PointerInputAnnotation* annotation = iter; unsigned int bti = annotations.m_argIndexMap.at(annotation->ArgumentNumber); context.Surface.SurfaceOffset[ bti ] = (DWORD)membuf.Size(); SurfaceStates.insert( std::make_pair( bti, SurfaceState( SURFACE_BUFFER, SURFACE_FORMAT_RAW, 0, false))); } for( auto iter : annotations.m_pointerArgument ) { PointerArgumentAnnotation* annotation = iter; unsigned int bti = annotations.m_argIndexMap.at(annotation->ArgumentNumber); context.Surface.SurfaceOffset[bti] = (DWORD)membuf.Size(); SurfaceStates.insert( std::make_pair( bti, SurfaceState( SURFACE_BUFFER, SURFACE_FORMAT_UNKNOWN, 0, false))); } // Images for( auto i : annotations.m_imageInputAnnotations ) { ImageArgumentAnnotation* annotation = i; if( annotation->IsFixedBindingTableIndex ) { bool isMultiSampleImage = false; SURFACE_TYPE surfaceType = SURFACE_UNKNOWN; switch( annotation->ImageType ) { case iOpenCL::IMAGE_MEMORY_OBJECT_BUFFER: surfaceType = SURFACE_BUFFER; break; case iOpenCL::IMAGE_MEMORY_OBJECT_1D: surfaceType = SURFACE_1D; break; case iOpenCL::IMAGE_MEMORY_OBJECT_1D_ARRAY: surfaceType = SURFACE_1D_ARRAY; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D: surfaceType = SURFACE_2D; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY: surfaceType = SURFACE_2D_ARRAY; break; case iOpenCL::IMAGE_MEMORY_OBJECT_3D: surfaceType = SURFACE_3D; break; case iOpenCL::IMAGE_MEMORY_OBJECT_CUBE: surfaceType = SURFACE_CUBE; break; case iOpenCL::IMAGE_MEMORY_OBJECT_CUBE_ARRAY: surfaceType = SURFACE_CUBE_ARRAY; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_DEPTH: surfaceType = SURFACE_2D; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY_DEPTH: surfaceType = SURFACE_2D_ARRAY; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_MEDIA: surfaceType = SURFACE_2D_MEDIA; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_MEDIA_BLOCK: surfaceType = SURFACE_2D_MEDIA_BLOCK; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_MSAA: surfaceType = SURFACE_2D; isMultiSampleImage = true; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_MSAA_DEPTH: surfaceType = SURFACE_2D; isMultiSampleImage = true; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY_MSAA: surfaceType = SURFACE_2D_ARRAY; isMultiSampleImage = true; break; case iOpenCL::IMAGE_MEMORY_OBJECT_2D_ARRAY_MSAA_DEPTH: surfaceType = SURFACE_2D_ARRAY; isMultiSampleImage = true; break; default: // unknown image annotation type IGC_ASSERT(0); retValue.Success = false; isMultiSampleImage = false; } unsigned int bti = annotations.m_argIndexMap.at(annotation->ArgumentNumber); SurfaceStates.insert( std::make_pair( bti, SurfaceState( surfaceType, SURFACE_FORMAT_UNKNOWN, 0, isMultiSampleImage))); } else { retValue.Success = false; IGC_ASSERT(0); } } if (annotations.m_printfBufferAnnotation != NULL) { unsigned int bti = annotations.m_argIndexMap.at(annotations.m_printfBufferAnnotation->ArgumentNumber); context.Surface.SurfaceOffset[bti] = (DWORD)membuf.Size(); SurfaceStates.insert( std::make_pair( bti, SurfaceState( SURFACE_BUFFER, SURFACE_FORMAT_RAW, 0, false))); } if (annotations.m_syncBufferAnnotation != NULL) { unsigned int bti = annotations.m_argIndexMap.at(annotations.m_syncBufferAnnotation->ArgumentNumber); context.Surface.SurfaceOffset[bti] = (DWORD)membuf.Size(); SurfaceStates.insert( std::make_pair( bti, SurfaceState( SURFACE_BUFFER, SURFACE_FORMAT_RAW, 0, false))); } // If GT-Pin is enabled, assign btis to GT-Pin's surfaces if (gtpinEnabled) { const unsigned numGTPinSurfaces = 2; IGC_ASSERT(GTPIN_IGC_OCL_NumberOfSurfaces() == numGTPinSurfaces); unsigned btiAssigned[numGTPinSurfaces]; for ( unsigned i = 0; i < numGTPinSurfaces; i++ ) { bool found = false; const int maxUseableBTI = 250; for (int bti=0; bti borderColorOffsets(numSamplers); if (borderColorOffsets.size() != numSamplers) { retValue.Success = false; } if( numSamplers && retValue.Success ) { // Handle border color state: if (m_Context && m_Context->m_DriverInfo.ProgrammableBorderColorInCompute()) { // Indirect states for argument samplers: for (DWORD i = 0; i < numArgumentSamplers && retValue.Success; i++) { DWORD borderColorOffset = AllocateSamplerIndirectState(G6HWC::g_cInitGfxSamplerIndirectState, membuf); borderColorOffsets[i] = borderColorOffset; } // Indirect states for inline samplers: for (DWORD i = 0; i < numInlineSamplers && retValue.Success; i++) { const SamplerInputAnnotation* samplerAnnotation = annotations.m_samplerInput[i]; G6HWC::SGfxSamplerIndirectState bcState = G6HWC::g_cInitGfxSamplerIndirectState; bcState.BorderColorRed = samplerAnnotation->BorderColorR; bcState.BorderColorGreen = samplerAnnotation->BorderColorG; bcState.BorderColorBlue = samplerAnnotation->BorderColorB; bcState.BorderColorAlpha = samplerAnnotation->BorderColorA; DWORD borderColorOffset = AllocateSamplerIndirectState(bcState, membuf); borderColorOffsets[i + numArgumentSamplers] = borderColorOffset; } } else { // If border color is not programmable, we can create only one that will be shared // among all sampler states used in a kernel. DWORD borderColorOffset = AllocateSamplerIndirectState(G6HWC::g_cInitGfxSamplerIndirectState, membuf); borderColorOffsets[0] = borderColorOffset; } // Now create sampler states: const DWORD alignment = HWCaps().SamplerStatePointerAlignSize; membuf.Align( alignment ); context.Dynamic.SamplerCount = numSamplers; context.Dynamic.SamplerArrayOffset = (DWORD)membuf.Size(); // We need to do this so patch.BorderColorOffset is set to any border color. context.Dynamic.SamplerBorderColorStateOffset = borderColorOffsets[0]; DWORD borderColorIndex = 0; DWORD borderColorStep = (m_Context && m_Context->m_DriverInfo.ProgrammableBorderColorInCompute()) ? 1 : 0; // First handle the sampler arguments for (auto i = annotations.m_samplerArgument.begin(); i != annotations.m_samplerArgument.end(); ++i, borderColorIndex += borderColorStep) { const SamplerArgumentAnnotation* samplerAnnotation = *i; context.Dynamic.SamplerOffset[samplerAnnotation->SamplerTableIndex] = (DWORD)membuf.Size(); // No need for sampler state for VME and VA... if( samplerAnnotation->SamplerType == SAMPLER_OBJECT_TEXTURE ) { SAMPLER_TEXTURE_ADDRESS_MODE addressMode = SAMPLER_TEXTURE_ADDRESS_MODE_CLAMP; SAMPLER_MAPFILTER_TYPE mapFilter = SAMPLER_MAPFILTER_POINT; SAMPLER_MIPFILTER_TYPE mipFilter = SAMPLER_MIPFILTER_NONE; SAMPLER_COMPARE_FUNC_TYPE compareFunc = SAMPLER_COMPARE_FUNC_NEVER; bool normalizedCoords = true; bool enable = true; IGC_ASSERT((m_Context && m_Context->m_DriverInfo.ProgrammableBorderColorInCompute()) || borderColorIndex == 0); retValue = AddSamplerState( enable, addressMode, addressMode, addressMode, mapFilter, mapFilter, mipFilter, normalizedCoords, compareFunc, borderColorOffsets[borderColorIndex], membuf ); if( !retValue.Success ) { IGC_ASSERT(0 && "Error during adding sampler state for sampler argument (index: samplerAnnotation->SamplerTableIndex, type: samplerAnnotation->SamplerType)"); break; } } // ... but for VA and VME we need to reserve size for sampler state on the heap: else { // Texture SAMPLER_STATE is located in the dynamic heap by // multiply the sampler index by 4 DWORDS. This is not true // for VA samplers because they are longer in length. This // means sampler index 4, for example, can point to multiple // locations in the dynamic heap depending on if a SAMPLE // or VA_SAMPLE instruction is used. We currently don't check // for overlapping SAMPLER_STATE. DWORD samplerStateSize = sizeof(G6HWC::SSharedStateSamplerState) * GetSamplerStateSizeMultiplier( samplerAnnotation->SamplerType ); membuf.AddPadding( samplerStateSize ); } } if( retValue.Success ) { IGC_ASSERT(!(m_Context && m_Context->m_DriverInfo.ProgrammableBorderColorInCompute()) || borderColorIndex == numArgumentSamplers); // And then the inline samplers for (auto i = annotations.m_samplerInput.begin(); i != annotations.m_samplerInput.end(); ++i, borderColorIndex += borderColorStep) { const SamplerInputAnnotation* samplerAnnotation = *i; context.Dynamic.SamplerOffset[samplerAnnotation->SamplerTableIndex] = (DWORD)membuf.Size( ); IGC_ASSERT(samplerAnnotation->SamplerType == SAMPLER_OBJECT_TEXTURE); bool enable = true; IGC_ASSERT((m_Context && m_Context->m_DriverInfo.ProgrammableBorderColorInCompute()) || borderColorIndex == 0); retValue = AddSamplerState( enable, samplerAnnotation->TCXAddressMode, samplerAnnotation->TCYAddressMode, samplerAnnotation->TCZAddressMode, samplerAnnotation->MagFilterType, samplerAnnotation->MinFilterType, samplerAnnotation->MipFilterType, samplerAnnotation->NormalizedCoords, samplerAnnotation->CompareFunc, borderColorOffsets[borderColorIndex], membuf ); if( !retValue.Success ) { IGC_ASSERT(0 && "Error during adding sampler state for inline sampler (index: samplerAnnotation->SamplerTableIndex, type: samplerAnnotation->SamplerType)"); break; } } } } // Interface Descriptor if( retValue.Success ) { unsigned int alignment = HWCaps().InterfaceDescriptorDataAlignSize; if( membuf.Align( alignment ) == false ) { retValue.Success = false; } context.Dynamic.InterfaceDescriptorDataOffset = (DWORD)membuf.Size(); if( retValue.Success ) { G6HWC::SMediaStateInterfaceDescriptorData ifdd = G6HWC::g_cInitMediaStateInterfaceDescriptorData; ifdd.DW1.Gen8 = G6HWC::g_cInitMediaStateInterfaceDescriptorDataDW1Gen8; ifdd.DW2.Gen8 = G6HWC::g_cInitMediaStateInterfaceDescriptorDataDW2Gen8; ifdd.DW3.Gen8 = G6HWC::g_cInitMediaStateInterfaceDescriptorDataDW3Gen8; ifdd.DW4.Gen8 = G6HWC::g_cInitMediaStateInterfaceDescriptorDataDW4Gen8; ifdd.DW5.Gen8 = G6HWC::g_cInitMediaStateInterfaceDescriptorDataDW5Gen8; ifdd.DW0.All.KernelStartPointer = context.Kernel.KernelOffset / HWCaps().KernelPointerAlignSize; ifdd.DW2.Gen8.SoftwareExceptionEnable = false; ifdd.DW2.Gen8.MaskStackExceptionEnable = false; ifdd.DW2.Gen8.IllegalOpcodeExceptionEnable = false; ifdd.DW2.Gen8.FloatingPointMode = G6HWC::GFXMEDIASTATE_FLOATING_POINT_IEEE_754; ifdd.DW2.Gen8.ThreadPriority = G6HWC::GFXMEDIASTATE_THREAD_PRIORITY_NORMAL; ifdd.DW2.Gen8.SingleProgramFlow = annotations.m_executionEnivronment.IsSingleProgramFlow; ifdd.DW3.Gen8.SamplerCount = context.Dynamic.SamplerCount; ifdd.DW3.Gen8.SamplerStatePointer = context.Dynamic.SamplerArrayOffset / HWCaps().SamplerStatePointerAlignSize; ifdd.DW4.Gen8.BindingTableEntryCount = context.Surface.SurfaceCount; ifdd.DW4.Gen8.BindingTablePointer = context.Surface.BindingTableOffset / HWCaps().BindingTableStatePointerAlignSize; ifdd.DW5.Gen8.ConstantURBEntryReadOffset = 0; ifdd.DW5.Gen8.ConstantURBEntryReadLength = 0; ifdd.DW7.Gen8.CrossThreadConstantDataReadLength = annotations.m_kernelProgram.ConstantBufferLength; if( membuf.Write( ifdd ) == false ) { retValue.Success = false; } #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) { G6HWC::DebugInterfaceDescriptorDataCommand( &ifdd, m_Platform, m_oclStateDebugMessagePrintOut ); } #endif } } return retValue; } DWORD CGen8OpenCLStateProcessor::AllocateSamplerIndirectState( const G6HWC::SGfxSamplerIndirectState& borderColor, Util::BinaryStream &membuf) { const DWORD alignment = HWCaps().DefaultColorPointerAlignSize; membuf.Align(alignment); DWORD samplerIndirectStateOffset = (DWORD)membuf.Size(); if (membuf.Write(borderColor) == false) { IGC_ASSERT(0); } #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) { G6HWC::DebugSamplerIndirectStateCommand( &samplerIndirectStateOffset, m_Platform, m_oclStateDebugMessagePrintOut ); } #endif return samplerIndirectStateOffset; } RETVAL CGen8OpenCLStateProcessor::CreatePatchList( const IGC::SOpenCLKernelInfo& annotations, const IGC::SOpenCLProgramInfo& programInfo, const IGC::CBTILayout& layout, const SStateProcessorContextGen8_0& context, const bool gtpinEnabled, Util::BinaryStream& membuf ) { RETVAL retValue = g_cInitRetValue; DWORD dataParameterStreamSize = 0; struct structhasDeviceEnqueue{ bool hasParentEvent; bool hasDefaultQueue; bool hasQueueArg; operator bool() const { return hasParentEvent && (hasDefaultQueue || hasQueueArg); }; structhasDeviceEnqueue() : hasParentEvent(false), hasDefaultQueue(false), hasQueueArg(false){}; }hasDeviceEnqueue; // Add a patch item for STATE_SIP, if required. if (retValue.Success && context.Kernel.SystemKernelPresent) { iOpenCL::SPatchStateSIP patch; memset(&patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_STATE_SIP; patch.Size = sizeof(patch); patch.SystemKernelOffset = context.Kernel.SystemKernelOffset; retValue = AddPatchItem( patch, membuf); } // Patch for MEDIA_VFE_STATE if( retValue.Success ) { const DWORD perThreadScratchSpaceSizeInBytes = annotations.m_executionEnivronment.PerThreadScratchSpace; if (perThreadScratchSpaceSizeInBytes > 0) { iOpenCL::SPatchMediaVFEState patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_MEDIA_VFE_STATE; patch.Size = sizeof( patch ); patch.ScratchSpaceOffset = 0; patch.PerThreadScratchSpace = iSTD::RoundPower2( iSTD::Max(perThreadScratchSpaceSizeInBytes, static_cast( sizeof(KILOBYTE) ) ) ); retValue = AddPatchItem( patch, membuf ); } } // Patch for MEDIA_VFE_STATE slot1 if (retValue.Success) { const DWORD perThreadScratchSpaceSizeInBytes = annotations.m_executionEnivronment.PerThreadScratchSpaceSlot1; if (perThreadScratchSpaceSizeInBytes > 0) { iOpenCL::SPatchMediaVFEState patch; memset(&patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_MEDIA_VFE_STATE_SLOT1; patch.Size = sizeof(patch); patch.ScratchSpaceOffset = 0; patch.PerThreadScratchSpace = iSTD::RoundPower2( iSTD::Max(perThreadScratchSpaceSizeInBytes, static_cast(sizeof(KILOBYTE)))); retValue = AddPatchItem( patch, membuf); } } // Patch for MEDIA_INTERFACE_DESCRIPTOR_LOAD if( retValue.Success ) { iOpenCL::SPatchMediaInterfaceDescriptorLoad patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_MEDIA_INTERFACE_DESCRIPTOR_LOAD; patch.Size = sizeof( patch ); patch.InterfaceDescriptorDataOffset = context.Dynamic.InterfaceDescriptorDataOffset; retValue = AddPatchItem( patch, membuf ); } if (annotations.m_HasInlineVmeSamplers) { iOpenCL::SPatchInlineVMESamplerInfo patch; iSTD::SafeMemSet( &patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_INLINE_VME_SAMPLER_INFO; patch.Size = sizeof(patch); retValue = AddPatchItem( patch, membuf); } // Patch for Samplers // Add patch items for samplers. if( retValue.Success && context.Dynamic.SamplerCount ) { // Add the patch item for the entire sampler state array. DWORD count = context.Dynamic.SamplerCount; DWORD offset = context.Dynamic.SamplerArrayOffset; DWORD borderColorOffset = context.Dynamic.SamplerBorderColorStateOffset; iOpenCL::SPatchSamplerStateArray patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_SAMPLER_STATE_ARRAY; patch.Size = sizeof( patch ); patch.Offset = offset; patch.Count = count; patch.BorderColorOffset = borderColorOffset; retValue = AddPatchItem( patch, membuf ); // Add a patch item for each sampler kernel argument. if( retValue.Success ) { for( SamplerArgumentIterator i = annotations.m_samplerArgument.begin(); i != annotations.m_samplerArgument.end(); ++i ) { SamplerArgumentAnnotation* samplerAnnotation = *i; iOpenCL::SPatchSamplerKernelArgument patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_SAMPLER_KERNEL_ARGUMENT; patch.Size = sizeof( patch ); patch.ArgumentNumber = samplerAnnotation->ArgumentNumber; patch.Offset = samplerAnnotation->IsBindlessAccess ? samplerAnnotation->PayloadPosition : context.Dynamic.SamplerOffset[samplerAnnotation->SamplerTableIndex]; patch.btiOffset = context.Dynamic.SamplerOffset[samplerAnnotation->SamplerTableIndex]; patch.LocationIndex = samplerAnnotation->LocationIndex; patch.LocationIndex2 = samplerAnnotation->LocationCount; patch.Type = samplerAnnotation->SamplerType; patch.needBindlessHandle = samplerAnnotation->IsBindlessAccess; patch.IsEmulationArgument = samplerAnnotation->IsEmulationArgument; if(samplerAnnotation->IsBindlessAccess) { dataParameterStreamSize = std::max( dataParameterStreamSize, samplerAnnotation->PayloadPosition + 8); } if( retValue.Success ) { retValue = AddPatchItem( patch, membuf ); } } } } // Patch for INTERFACE_DESCRIPTOR_DATA if( retValue.Success ) { iOpenCL::SPatchInterfaceDescriptorData patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_INTERFACE_DESCRIPTOR_DATA; patch.Size = sizeof( patch ); patch.Offset = context.Dynamic.InterfaceDescriptorDataOffset; patch.SamplerStateOffset = context.Dynamic.SamplerArrayOffset; patch.KernelOffset = context.Kernel.KernelOffset; patch.BindingTableOffset = context.Surface.BindingTableOffset; retValue = AddPatchItem( patch, membuf ); } // Add a patch item for BINDING_TABLE_STATE. if( retValue.Success ) { iOpenCL::SPatchBindingTableState patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_BINDING_TABLE_STATE; patch.Size = sizeof( patch ); patch.Offset = context.Surface.BindingTableOffset; patch.Count = context.Surface.SurfaceCount; patch.SurfaceStateOffset = context.Surface.SurfaceArrayOffset; retValue = AddPatchItem( patch, membuf ); } // Patch for SRVs & UAVs if( retValue.Success ) { bool transformable = InlineSamplersAllow3DImageTransformation(annotations); for (ImageArgumentIterator i = annotations.m_imageInputAnnotations.begin(); i != annotations.m_imageInputAnnotations.end(); ++i ) { ImageArgumentAnnotation* imageInput = *i; iOpenCL::SPatchImageMemoryObjectKernelArgument patch; memset( &patch, 0, sizeof( patch ) ); unsigned int bti = annotations.m_argIndexMap.at(imageInput->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_IMAGE_MEMORY_OBJECT_KERNEL_ARGUMENT; patch.Size = sizeof( patch ); patch.ArgumentNumber = imageInput->ArgumentNumber; patch.Offset = imageInput->IsBindlessAccess ? imageInput->PayloadPosition : context.Surface.SurfaceOffset[bti]; patch.btiOffset = context.Surface.SurfaceOffset[bti]; patch.Type = imageInput->ImageType; patch.Writeable = imageInput->Writeable; patch.LocationIndex = imageInput->LocationIndex; patch.LocationIndex2 = imageInput->LocationCount; patch.needBindlessHandle = imageInput->IsBindlessAccess; patch.IsEmulationArgument = imageInput->IsEmulationArgument; if(imageInput->IsBindlessAccess) { dataParameterStreamSize = std::max( dataParameterStreamSize, imageInput->PayloadPosition + 8); } patch.Transformable = transformable && (imageInput->AccessedByIntCoords && !imageInput->AccessedByFloatCoords && imageInput->ImageType == IMAGE_MEMORY_OBJECT_3D); if( retValue.Success ) { retValue = AddPatchItem( patch, membuf ); } } } // Patch for TGSM if( retValue.Success ) { if( annotations.m_executionEnivronment.SumFixedTGSMSizes > 0 ) { iOpenCL::SPatchAllocateLocalSurface patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_LOCAL_SURFACE; patch.Size = sizeof( patch ); patch.TotalInlineLocalMemorySize = annotations.m_executionEnivronment.SumFixedTGSMSizes; retValue = AddPatchItem( patch, membuf ); } } // Patch for Private Memory // Patch for Surface State Scratch Space // Patch for ALLOCATE_SIP_SURFACE if (retValue.Success && m_Context && m_Context->m_InternalOptions.KernelDebugEnable) { unsigned int bti = layout.GetSystemThreadBindingTableIndex(); iOpenCL::SPatchAllocateSystemThreadSurface patch; memset(&patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_SIP_SURFACE; patch.Size = sizeof(patch); patch.Offset = context.Surface.SurfaceOffset[bti]; patch.BTI = bti; patch.PerThreadSystemThreadSurfaceSize = (unsigned int)0x1800;// SIP::cGen8SIPThreadScratchSize; retValue = AddPatchItem( patch, membuf); } // Patch for DataParameterStream // Patch information for variable TGSM data parameters: if( retValue.Success ) { for( LocalArgumentIterator i = annotations.m_localPointerArgument.begin(); i != annotations.m_localPointerArgument.end(); ++i ) { LocalArgumentAnnotation* localArg = *i; iOpenCL::SPatchDataParameterBuffer patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_DATA_PARAMETER_BUFFER; patch.Size = sizeof( patch ); patch.ArgumentNumber = localArg->ArgumentNumber; patch.DataSize = localArg->PayloadSizeInBytes; patch.SourceOffset = localArg->Alignment; patch.Offset = localArg->PayloadPosition; patch.LocationIndex = localArg->LocationIndex; patch.LocationIndex2 = localArg->LocationCount; patch.Type = iOpenCL::DATA_PARAMETER_SUM_OF_LOCAL_MEMORY_OBJECT_ARGUMENT_SIZES; dataParameterStreamSize = std::max( dataParameterStreamSize, localArg->PayloadPosition + localArg->PayloadSizeInBytes ); if( retValue.Success ) { retValue = AddPatchItem( patch, membuf ); } } } // Constant Input Parameters if( retValue.Success ) { for( ConstantInputIterator i = annotations.m_constantInputAnnotation.begin(); i != annotations.m_constantInputAnnotation.end(); ++i ) { ConstantInputAnnotation* constInput = *i; iOpenCL::SPatchDataParameterBuffer patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_DATA_PARAMETER_BUFFER; patch.Size = sizeof( patch ); patch.ArgumentNumber = constInput->ArgumentNumber; patch.DataSize = constInput->PayloadSizeInBytes; patch.SourceOffset = constInput->Offset; patch.Offset = constInput->PayloadPosition; patch.Type = constInput->ConstantType; if( patch.Type == iOpenCL::DATA_PARAMETER_PARENT_EVENT ) { hasDeviceEnqueue.hasParentEvent = true; } patch.LocationIndex = constInput->LocationIndex; patch.LocationIndex2 = constInput->LocationCount; dataParameterStreamSize = std::max( dataParameterStreamSize, constInput->PayloadPosition + constInput->PayloadSizeInBytes ); if( retValue.Success ) { retValue = AddPatchItem( patch, membuf ); } } } // Pointer Kernel Arguments if( retValue.Success ) { for( PointerArgumentIterator i = annotations.m_pointerArgument.begin(); i != annotations.m_pointerArgument.end(); ++i ) { PointerArgumentAnnotation* ptrArg = *i; if( ptrArg->IsStateless == true || ptrArg->IsBindlessAccess) { if( ptrArg->AddressSpace == KERNEL_ARGUMENT_ADDRESS_SPACE_GLOBAL ) { iOpenCL::SPatchStatelessGlobalMemoryObjectKernelArgument patch; memset( &patch, 0, sizeof( patch ) ); unsigned int bti = annotations.m_argIndexMap.at(ptrArg->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_STATELESS_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT; patch.Size = sizeof( patch ); patch.ArgumentNumber = ptrArg->ArgumentNumber; patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[ bti ]; patch.DataParamOffset = ptrArg->PayloadPosition; patch.DataParamSize = ptrArg->PayloadSizeInBytes; patch.LocationIndex = ptrArg->LocationIndex; patch.LocationIndex2 = ptrArg->LocationCount; patch.IsEmulationArgument = ptrArg->IsEmulationArgument; dataParameterStreamSize = std::max( dataParameterStreamSize, ptrArg->PayloadPosition + ptrArg->PayloadSizeInBytes ); retValue = AddPatchItem( patch, membuf ); } else if(ptrArg->AddressSpace == KERNEL_ARGUMENT_ADDRESS_SPACE_CONSTANT) { iOpenCL::SPatchStatelessConstantMemoryObjectKernelArgument patch; memset( &patch, 0, sizeof( patch ) ); unsigned int bti = annotations.m_argIndexMap.at(ptrArg->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_STATELESS_CONSTANT_MEMORY_OBJECT_KERNEL_ARGUMENT; patch.Size = sizeof( patch ); patch.ArgumentNumber = ptrArg->ArgumentNumber; patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[ bti ]; patch.DataParamOffset = ptrArg->PayloadPosition; patch.DataParamSize = ptrArg->PayloadSizeInBytes; patch.LocationIndex = ptrArg->LocationIndex; patch.LocationIndex2 = ptrArg->LocationCount; patch.IsEmulationArgument = ptrArg->IsEmulationArgument; dataParameterStreamSize = std::max( dataParameterStreamSize, ptrArg->PayloadPosition + ptrArg->PayloadSizeInBytes ); retValue = AddPatchItem( patch, membuf ); } else if(ptrArg->AddressSpace == KERNEL_ARGUMENT_ADDRESS_SPACE_DEVICE_QUEUE) { iOpenCL::SPatchStatelessDeviceQueueKernelArgument patch; memset(&patch, 0, sizeof(patch)); hasDeviceEnqueue.hasQueueArg = true; unsigned int bti = annotations.m_argIndexMap.at(ptrArg->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_STATELESS_DEVICE_QUEUE_KERNEL_ARGUMENT; patch.Size = sizeof(patch); patch.ArgumentNumber = ptrArg->ArgumentNumber; patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[bti];; patch.DataParamOffset = ptrArg->PayloadPosition; patch.DataParamSize = ptrArg->PayloadSizeInBytes; patch.LocationIndex = ptrArg->LocationIndex; patch.LocationIndex2 = ptrArg->LocationCount; patch.IsEmulationArgument = ptrArg->IsEmulationArgument; dataParameterStreamSize = std::max( dataParameterStreamSize, ptrArg->PayloadPosition + ptrArg->PayloadSizeInBytes); retValue = AddPatchItem( patch, membuf); } else { retValue.Success = false; IGC_ASSERT(0); } } else { // Pointer Kernel arguments must be stateless retValue.Success = false; } } } // Patch for Printf Output Buffer Offset if (retValue.Success) { if (annotations.m_printfBufferAnnotation != nullptr) { iOpenCL::PrintfBufferAnnotation *printfBufAnn = annotations.m_printfBufferAnnotation; iOpenCL::SPatchAllocateStatelessPrintfSurface patch; memset(&patch, 0, sizeof(patch)); unsigned int bti = annotations.m_argIndexMap.at(printfBufAnn->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_PRINTF_SURFACE; patch.Size = sizeof(patch); patch.PrintfSurfaceIndex = printfBufAnn->Index; patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[bti]; patch.DataParamOffset = printfBufAnn->PayloadPosition; patch.DataParamSize = printfBufAnn->DataSize; dataParameterStreamSize = std::max( dataParameterStreamSize, printfBufAnn->PayloadPosition + printfBufAnn->DataSize ); retValue = AddPatchItem(patch, membuf); } } // Patch for Sync Buffer Offset if (retValue.Success) { if (annotations.m_syncBufferAnnotation != nullptr) { iOpenCL::SyncBufferAnnotation* syncBufAnn = annotations.m_syncBufferAnnotation; iOpenCL::SPatchAllocateSyncBuffer patch; memset(&patch, 0, sizeof(patch)); unsigned int bti = annotations.m_argIndexMap.at(syncBufAnn->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_SYNC_BUFFER; patch.Size = sizeof(patch); patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[bti]; patch.DataParamOffset = syncBufAnn->PayloadPosition; patch.DataParamSize = syncBufAnn->DataSize; dataParameterStreamSize = std::max( dataParameterStreamSize, syncBufAnn->PayloadPosition + syncBufAnn->DataSize); retValue = AddPatchItem(patch, membuf); } } // Pointer inputs with initializer if( retValue.Success ) { for( PointerInputIterator i = annotations.m_pointerInput.begin(); i != annotations.m_pointerInput.end(); ++i ) { PointerInputAnnotation* ptrArg = *i; if( ptrArg->IsStateless == true ) { if(ptrArg->AddressSpace == iOpenCL::KERNEL_ARGUMENT_ADDRESS_SPACE_CONSTANT) { iOpenCL::SPatchAllocateStatelessConstantMemorySurfaceWithInitialization patch; memset( &patch, 0, sizeof( patch ) ); unsigned int bti = annotations.m_argIndexMap.at(ptrArg->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_CONSTANT_MEMORY_SURFACE_WITH_INITIALIZATION; patch.Size = sizeof( patch ); patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[ bti ]; patch.DataParamOffset = ptrArg->PayloadPosition; patch.DataParamSize = ptrArg->PayloadSizeInBytes; patch.ConstantBufferIndex = DEFAULT_CONSTANT_BUFFER_INDEX; dataParameterStreamSize = std::max( dataParameterStreamSize, ptrArg->PayloadPosition + ptrArg->PayloadSizeInBytes ); retValue = AddPatchItem( patch, membuf ); } else if(ptrArg->AddressSpace == iOpenCL::KERNEL_ARGUMENT_ADDRESS_SPACE_GLOBAL) { iOpenCL::SPatchAllocateStatelessGlobalMemorySurfaceWithInitialization patch; memset( &patch, 0, sizeof( patch ) ); unsigned int bti = annotations.m_argIndexMap.at(ptrArg->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_GLOBAL_MEMORY_SURFACE_WITH_INITIALIZATION; patch.Size = sizeof( patch ); patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[ bti ]; patch.DataParamOffset = ptrArg->PayloadPosition; patch.DataParamSize = ptrArg->PayloadSizeInBytes; patch.GlobalBufferIndex = 0; dataParameterStreamSize = std::max( dataParameterStreamSize, ptrArg->PayloadPosition + ptrArg->PayloadSizeInBytes ); retValue = AddPatchItem( patch, membuf ); } else if(ptrArg->AddressSpace == iOpenCL::KERNEL_ARGUMENT_ADDRESS_SPACE_PRIVATE) { iOpenCL::SPatchAllocateStatelessPrivateSurface patch; memset( &patch, 0, sizeof( patch ) ); PrivateInputAnnotation* ptrArg = static_cast(*i); unsigned int bti = annotations.m_argIndexMap.at(ptrArg->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_PRIVATE_MEMORY; patch.Size = sizeof( patch ); patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[ bti ]; patch.PerThreadPrivateMemorySize = std::max((DWORD)IGC_GET_FLAG_VALUE(ForcePerThreadPrivateMemorySize), ptrArg->PerThreadPrivateMemorySize); patch.DataParamOffset = ptrArg->PayloadPosition; patch.DataParamSize = ptrArg->PayloadSizeInBytes; dataParameterStreamSize = std::max( dataParameterStreamSize, ptrArg->PayloadPosition + ptrArg->PayloadSizeInBytes ); retValue = AddPatchItem( patch, membuf ); } else if(ptrArg->AddressSpace == ADDRESS_SPACE_INTERNAL_DEFAULT_DEVICE_QUEUE) { iOpenCL::SPatchAllocateStatelessDefaultDeviceQueueSurface patch; memset(&patch, 0, sizeof(patch)); hasDeviceEnqueue.hasDefaultQueue = true; unsigned int bti = annotations.m_argIndexMap.at(ptrArg->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_DEFAULT_DEVICE_QUEUE_SURFACE; patch.Size = sizeof(patch); patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[bti]; patch.DataParamOffset = ptrArg->PayloadPosition; patch.DataParamSize = ptrArg->PayloadSizeInBytes; dataParameterStreamSize = std::max( dataParameterStreamSize, ptrArg->PayloadPosition + ptrArg->PayloadSizeInBytes); retValue = AddPatchItem( patch, membuf); } else if(ptrArg->AddressSpace == ADDRESS_SPACE_INTERNAL_EVENT_POOL) { iOpenCL::SPatchAllocateStatelessEventPoolSurface patch; memset(&patch, 0, sizeof(patch)); unsigned int bti = annotations.m_argIndexMap.at(ptrArg->ArgumentNumber); patch.Token = iOpenCL::PATCH_TOKEN_ALLOCATE_STATELESS_EVENT_POOL_SURFACE; patch.Size = sizeof(patch); patch.SurfaceStateHeapOffset = context.Surface.SurfaceOffset[bti]; patch.DataParamOffset = ptrArg->PayloadPosition; patch.DataParamSize = ptrArg->PayloadSizeInBytes; dataParameterStreamSize = std::max( dataParameterStreamSize, ptrArg->PayloadPosition + ptrArg->PayloadSizeInBytes); retValue = AddPatchItem( patch, membuf); } else { // Only constant and private address space is supported for now. retValue.Success = false; } } else { // Pointer inputs must be stateless retValue.Success = false; } } } // Constant Arguments if( retValue.Success ) { for( ConstantArgumentIterator i = annotations.m_constantArgumentAnnotation.begin(); i != annotations.m_constantArgumentAnnotation.end(); ++i ) { ConstantArgumentAnnotation* constInput = *i; iOpenCL::SPatchDataParameterBuffer patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_DATA_PARAMETER_BUFFER; patch.Size = sizeof( patch ); patch.ArgumentNumber = constInput->ArgumentNumber; //Datasize = PayloadSize, SourceOffset = 0, is wrong for everything > 32-bit patch.DataSize = constInput->PayloadSizeInBytes; patch.SourceOffset = constInput->Offset; patch.Offset = constInput->PayloadPosition; patch.Type = iOpenCL::DATA_PARAMETER_KERNEL_ARGUMENT; patch.LocationIndex = constInput->LocationIndex; patch.LocationIndex2 = constInput->LocationCount; patch.IsEmulationArgument = constInput->IsEmulationArgument; dataParameterStreamSize = std::max( dataParameterStreamSize, constInput->PayloadPosition + constInput->PayloadSizeInBytes ); if( retValue.Success ) { retValue = AddPatchItem( patch, membuf ); } } } if (retValue.Success && annotations.m_startGAS != NULL) { const iOpenCL::StartGASAnnotation* startGAS = annotations.m_startGAS; iOpenCL::SPatchDataParameterBuffer patch; memset(&patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_DATA_PARAMETER_BUFFER; patch.Size = sizeof(patch); patch.Type = iOpenCL::DATA_PARAMETER_LOCAL_MEMORY_STATELESS_WINDOW_START_ADDRESS; patch.Offset = startGAS->Offset; patch.DataSize = startGAS->gpuPointerSizeInBytes; dataParameterStreamSize = std::max( dataParameterStreamSize, startGAS->Offset + startGAS->gpuPointerSizeInBytes); retValue = AddPatchItem(patch, membuf); } if (retValue.Success && (annotations.m_WindowSizeGAS != NULL)) { iOpenCL::SPatchDataParameterBuffer patch; memset(&patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_DATA_PARAMETER_BUFFER; patch.Size = sizeof(patch); patch.Type = iOpenCL::DATA_PARAMETER_LOCAL_MEMORY_STATELESS_WINDOW_SIZE; patch.Offset = annotations.m_WindowSizeGAS->Offset; patch.DataSize = iOpenCL::DATA_PARAMETER_DATA_SIZE; dataParameterStreamSize = std::max( dataParameterStreamSize, annotations.m_WindowSizeGAS->Offset + iOpenCL::DATA_PARAMETER_DATA_SIZE); retValue = AddPatchItem(patch, membuf); } if (retValue.Success && (annotations.m_PrivateMemSize != NULL)) { iOpenCL::SPatchDataParameterBuffer patch; memset(&patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_DATA_PARAMETER_BUFFER; patch.Size = sizeof(patch); patch.Type = iOpenCL::DATA_PARAMETER_PRIVATE_MEMORY_STATELESS_SIZE; patch.Offset = annotations.m_PrivateMemSize->Offset; patch.DataSize = iOpenCL::DATA_PARAMETER_DATA_SIZE; retValue = AddPatchItem(patch, membuf); dataParameterStreamSize = std::max( dataParameterStreamSize, annotations.m_PrivateMemSize->Offset + iOpenCL::DATA_PARAMETER_DATA_SIZE ); } // Payload must be a multiple of a GRF register dataParameterStreamSize += GetAlignmentOffset(dataParameterStreamSize, CPlatform(m_Platform).getGRFSize()); if( retValue.Success ) { iOpenCL::SPatchDataParameterStream patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_DATA_PARAMETER_STREAM; patch.Size = sizeof( patch ); patch.DataParameterStreamSize = dataParameterStreamSize; retValue = AddPatchItem( patch, membuf ); } // Patch for Thread Payload if( retValue.Success ) { iOpenCL::SPatchThreadPayload patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_THREAD_PAYLOAD; patch.Size = sizeof( patch ); patch.HeaderPresent = false; patch.LocalIDXPresent = annotations.m_threadPayload.HasLocalIDx; patch.LocalIDYPresent = annotations.m_threadPayload.HasLocalIDy; patch.LocalIDZPresent = annotations.m_threadPayload.HasLocalIDz; patch.GetGlobalOffsetPresent = annotations.m_threadPayload.HasGlobalIDOffset; patch.GetGroupIDPresent = annotations.m_threadPayload.HasGroupID; patch.GetLocalIDPresent = annotations.m_threadPayload.HasLocalID; patch.StageInGridOriginPresent = annotations.m_threadPayload.HasStageInGridOrigin; patch.StageInGridSizePresent = annotations.m_threadPayload.HasStageInGridSize; patch.IndirectPayloadStorage = annotations.m_threadPayload.CompiledForIndirectPayloadStorage; patch.UnusedPerThreadConstantPresent = annotations.m_threadPayload.UnusedPerThreadConstantPresent; patch.OffsetToSkipPerThreadDataLoad = annotations.m_threadPayload.OffsetToSkipPerThreadDataLoad; patch.OffsetToSkipSetFFIDGP = annotations.m_threadPayload.OffsetToSkipSetFFIDGP; patch.PassInlineData = annotations.m_threadPayload.PassInlineData; retValue = AddPatchItem( patch, membuf ); } // Patch for Execution Enivronment if( retValue.Success ) { iOpenCL::SPatchExecutionEnvironment patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_EXECUTION_ENVIRONMENT; patch.Size = sizeof( patch ); if( annotations.m_executionEnivronment.HasFixedWorkGroupSize ) { patch.RequiredWorkGroupSizeX = annotations.m_executionEnivronment.FixedWorkgroupSize[0]; patch.RequiredWorkGroupSizeY = annotations.m_executionEnivronment.FixedWorkgroupSize[1]; patch.RequiredWorkGroupSizeZ = annotations.m_executionEnivronment.FixedWorkgroupSize[2]; } patch.WorkgroupWalkOrderDims = 0; patch.WorkgroupWalkOrderDims |= annotations.m_executionEnivronment.WorkgroupWalkOrder[0]; patch.WorkgroupWalkOrderDims |= annotations.m_executionEnivronment.WorkgroupWalkOrder[1] << 2; patch.WorkgroupWalkOrderDims |= annotations.m_executionEnivronment.WorkgroupWalkOrder[2] << 4; patch.CompiledSIMD32 = ( annotations.m_executionEnivronment.CompiledSIMDSize == 32 ); patch.CompiledSIMD16 = ( annotations.m_executionEnivronment.CompiledSIMDSize == 16 ); patch.CompiledSIMD8 = ( annotations.m_executionEnivronment.CompiledSIMDSize == 8 ); if (annotations.m_executionEnivronment.CompiledSIMDSize == 1) { patch.LargestCompiledSIMDSize = 1; } else { patch.LargestCompiledSIMDSize = 8; patch.LargestCompiledSIMDSize = patch.CompiledSIMD16 ? 16 : patch.LargestCompiledSIMDSize; patch.LargestCompiledSIMDSize = patch.CompiledSIMD32 ? 32 : patch.LargestCompiledSIMDSize; } patch.HasBarriers = annotations.m_executionEnivronment.HasBarriers; patch.DisableMidThreadPreemption = annotations.m_executionEnivronment.DisableMidThreadPreemption; patch.UsesStatelessSpillFill = (annotations.m_executionEnivronment.PerThreadScratchSpace > 0); patch.UsesMultiScratchSpaces = false; patch.HasDeviceEnqueue = (bool)hasDeviceEnqueue; patch.UsesFencesForReadWriteImages = annotations.m_executionEnivronment.HasReadWriteImages; patch.IsInitializer = annotations.m_executionEnivronment.IsInitializer; patch.IsFinalizer = annotations.m_executionEnivronment.IsFinalizer; patch.SubgroupIndependentForwardProgressRequired = annotations.m_executionEnivronment.SubgroupIndependentForwardProgressRequired; patch.CompiledSubGroupsNumber = annotations.m_executionEnivronment.CompiledSubGroupsNumber; patch.CompiledForGreaterThan4GBBuffers = annotations.m_executionEnivronment.CompiledForGreaterThan4GBBuffers; patch.NumGRFRequired = annotations.m_executionEnivronment.NumGRFRequired; patch.HasGlobalAtomics = annotations.m_executionEnivronment.HasGlobalAtomics; retValue = AddPatchItem( patch, membuf ); } // Patch for Kernel Attributes if( retValue.Success ) { retValue = AddKernelAttributePatchItems(annotations, membuf); } // Patch for Kernel Arguments if( retValue.Success ) { retValue = AddKernelArgumentPatchItems(annotations, membuf); } // Patch for String Annotations if( retValue.Success ) { for( PrintfStringIterator i = annotations.m_printfStringAnnotations.begin(); i != annotations.m_printfStringAnnotations.end(); i++ ) { PrintfStringAnnotation *stringAnn = *i; iOpenCL::SPatchString patch; memset( &patch, 0, sizeof( patch ) ); uint32_t alignedStringSize = 0; patch.Token = iOpenCL::PATCH_TOKEN_STRING; patch.Size = sizeof( patch ); patch.Index = stringAnn->Index; std::streamsize tokenStart = membuf.Size(); if( !membuf.Write( patch ) ) { retValue.Success = false; return retValue; } if( retValue.Success ) { retValue = AddStringPatchItem( stringAnn->StringData, membuf, alignedStringSize ); } patch.StringSize = alignedStringSize; patch.Size += alignedStringSize; membuf.WriteAt( patch, tokenStart ); #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) DebugPatchList(membuf.GetLinearPointer() + tokenStart, patch.Size, m_oclStateDebugMessagePrintOut); #endif } } // Patch for GT-Pin surfaces if (gtpinEnabled) { for (int i = 0; i < GTPIN_IGC_OCL_NumberOfSurfaces(); i++) { if (retValue.Success) { const unsigned bti = GTPIN_IGC_OCL_GetSurfaceBTI(i); const unsigned offset = context.Surface.SurfaceOffset[bti]; const unsigned param = GTPIN_IGC_OCL_GetSurfaceKernelArgNo(i); // patched as global memory object iOpenCL::SPatchGlobalMemoryObjectKernelArgument patch; memset(&patch, 0, sizeof(patch)); patch.Token = iOpenCL::PATCH_TOKEN_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT; patch.Size = sizeof(patch); patch.ArgumentNumber = param; patch.Offset = offset; retValue = AddPatchItem(patch, membuf); } } } // Patch for GTPin output structure if (retValue.Success) { iOpenCL::SPatchItemHeader patch; memset(&patch, 0, sizeof(patch)); patch.Token = PATCH_TOKEN_GTPIN_INFO; unsigned int size = 0; void* buffer = nullptr; const IGC::SKernelProgram* program = &(annotations.m_kernelProgram); if (annotations.m_executionEnivronment.CompiledSIMDSize == 8) { buffer = program->simd8.m_gtpinBuffer; size = program->simd8.m_gtpinBufferSize; } else if (annotations.m_executionEnivronment.CompiledSIMDSize == 16) { buffer = program->simd16.m_gtpinBuffer; size = program->simd16.m_gtpinBufferSize; } else if (annotations.m_executionEnivronment.CompiledSIMDSize == 32) { buffer = program->simd32.m_gtpinBuffer; size = program->simd32.m_gtpinBufferSize; } if (size > 0) { patch.Size = sizeof(patch) + size; retValue = AddPatchItem(patch, membuf); if (!membuf.Write((const char*)buffer, size)) { retValue.Success = false; return retValue; } freeBlock(buffer); } } // Patch for symbol table if (retValue.Success) { iOpenCL::SPatchFunctionTableInfo patch; memset(&patch, 0, sizeof(patch)); patch.Token = PATCH_TOKEN_PROGRAM_SYMBOL_TABLE; uint32_t size = 0; uint32_t entries = 0; void* buffer = nullptr; const IGC::SKernelProgram* program = &(annotations.m_kernelProgram); if (annotations.m_executionEnivronment.CompiledSIMDSize == 8) { buffer = program->simd8.m_funcSymbolTable; size = program->simd8.m_funcSymbolTableSize; entries = program->simd8.m_funcSymbolTableEntries; } else if (annotations.m_executionEnivronment.CompiledSIMDSize == 16) { buffer = program->simd16.m_funcSymbolTable; size = program->simd16.m_funcSymbolTableSize; entries = program->simd16.m_funcSymbolTableEntries; } else if (annotations.m_executionEnivronment.CompiledSIMDSize == 32) { buffer = program->simd32.m_funcSymbolTable; size = program->simd32.m_funcSymbolTableSize; entries = program->simd32.m_funcSymbolTableEntries; } if (size > 0) { patch.Size = sizeof(patch) + size; patch.NumEntries = entries; std::streamsize tokenStart = membuf.Size(); if (!membuf.Write(patch)) { retValue.Success = false; return retValue; } if (!membuf.Write((const char*)buffer, size)) { retValue.Success = false; return retValue; } free(buffer); #if defined(_DEBUG) || defined(_INTERNAL) || defined(_RELEASE_INTERNAL) DebugPatchList(membuf.GetLinearPointer() + tokenStart, patch.Size, m_oclStateDebugMessagePrintOut); #endif } } // Patch for relocation table if (retValue.Success) { iOpenCL::SPatchFunctionTableInfo patch; memset(&patch, 0, sizeof(patch)); patch.Token = PATCH_TOKEN_PROGRAM_RELOCATION_TABLE; uint32_t size = 0; uint32_t entries = 0; void* buffer = nullptr; const IGC::SKernelProgram* program = &(annotations.m_kernelProgram); if (annotations.m_executionEnivronment.CompiledSIMDSize == 8) { buffer = program->simd8.m_funcRelocationTable; size = program->simd8.m_funcRelocationTableSize; entries = program->simd8.m_funcRelocationTableEntries; } else if (annotations.m_executionEnivronment.CompiledSIMDSize == 16) { buffer = program->simd16.m_funcRelocationTable; size = program->simd16.m_funcRelocationTableSize; entries = program->simd16.m_funcRelocationTableEntries; } else if (annotations.m_executionEnivronment.CompiledSIMDSize == 32) { buffer = program->simd32.m_funcRelocationTable; size = program->simd32.m_funcRelocationTableSize; entries = program->simd32.m_funcRelocationTableEntries; } if (size > 0) { patch.Size = sizeof(patch) + size; patch.NumEntries = entries; std::streamsize tokenStart = membuf.Size(); if (!membuf.Write(patch)) { retValue.Success = false; return retValue; } if (!membuf.Write((const char*)buffer, size)) { retValue.Success = false; return retValue; } freeBlock(buffer); #if defined(_DEBUG) || defined(_INTERNAL) || defined(_RELEASE_INTERNAL) DebugPatchList(membuf.GetLinearPointer() + tokenStart, patch.Size, m_oclStateDebugMessagePrintOut); #endif } } return retValue; } inline RETVAL CGen8OpenCLStateProcessor::AddStringPatchItem( const std::string& str, Util::BinaryStream& membuf, uint32_t& bytesWritten ) const { RETVAL retValue = g_cInitRetValue; unsigned int length = (unsigned int)str.size(); bytesWritten = iSTD::Align( length + 1, sizeof( uint32_t ) ); if (!membuf.Write(str.data(), length)) { retValue.Success = false; return retValue; } for( ; length < bytesWritten; length++) { if (!membuf.Write('\0')) { retValue.Success = false; return retValue; } } return retValue; } RETVAL CGen8OpenCLStateProcessor::AddKernelAttributePatchItems( const IGC::SOpenCLKernelInfo& annotations, Util::BinaryStream& membuf ) { RETVAL retValue = g_cInitRetValue; iOpenCL::SPatchKernelAttributesInfo patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_KERNEL_ATTRIBUTES_INFO; patch.Size = sizeof( patch ); patch.AttributesSize = 0; // We need to start writing after the token, but we don't know the sizes yet. // So write it as place-holder, then replace with the real token. std::streamsize tokenStart = membuf.Size(); if( !membuf.Write( patch ) ) { retValue.Success = false; return retValue; } if( retValue.Success ) { std::istringstream buf(annotations.m_kernelAttributeInfo); std::istream_iterator< std::string > beg(buf), end; std::vector tokens(beg, end); std::string filteredAttributes; for( auto &s: tokens ) { for( int index = 0; index < numAllowedAttributes; index++ ) { if( s.find( allowedAttributes[index] ) != std::string::npos ) { if( filteredAttributes.length() > 0 ) { filteredAttributes += " "; } filteredAttributes += s; break; } } } retValue = AddStringPatchItem( filteredAttributes, membuf, patch.AttributesSize ); patch.Size += patch.AttributesSize; } if( retValue.Success && !membuf.WriteAt( patch, tokenStart ) ) { retValue.Success = false; return retValue; } #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) DebugPatchList(membuf.GetLinearPointer() + tokenStart, patch.Size, m_oclStateDebugMessagePrintOut); #endif return retValue; } RETVAL CGen8OpenCLStateProcessor::AddKernelArgumentPatchItems( const IGC::SOpenCLKernelInfo& annotations, Util::BinaryStream& membuf ) { RETVAL retValue = g_cInitRetValue; const std::vector& kernelArgInfo = annotations.m_kernelArgInfo; int index = 0; for(auto argInfo : kernelArgInfo) { iOpenCL::SPatchKernelArgumentInfo patch; memset( &patch, 0, sizeof( patch ) ); patch.Token = iOpenCL::PATCH_TOKEN_KERNEL_ARGUMENT_INFO; patch.Size = sizeof( patch ); patch.ArgumentNumber = index; // We need to start writing after the token, but we don't know the sizes yet. // So write it as place-holder, then replace with the real token. std::streamsize tokenStart = membuf.Size(); if( !membuf.Write( patch ) ) { retValue.Success = false; return retValue; } if( retValue.Success ) { retValue = AddStringPatchItem( argInfo->AddressQualifier, membuf, patch.AddressQualifierSize ); patch.Size += patch.AddressQualifierSize; } if( retValue.Success ) { retValue = AddStringPatchItem( argInfo->AccessQualifier, membuf, patch.AccessQualifierSize ); patch.Size += patch.AccessQualifierSize; } if( retValue.Success ) { retValue = AddStringPatchItem( argInfo->ArgumentName, membuf, patch.ArgumentNameSize ); patch.Size += patch.ArgumentNameSize; } if( retValue.Success ) { retValue = AddStringPatchItem( argInfo->TypeName, membuf, patch.TypeNameSize ); patch.Size += patch.TypeNameSize; } if( retValue.Success ) { retValue = AddStringPatchItem( argInfo->TypeQualifier, membuf, patch.TypeQualifierSize ); patch.Size += patch.TypeQualifierSize; } if( retValue.Success && !membuf.WriteAt( patch, tokenStart ) ) { retValue.Success = false; return retValue; } #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) DebugPatchList(membuf.GetLinearPointer() + tokenStart, patch.Size, m_oclStateDebugMessagePrintOut); #endif index++; } return retValue; } RETVAL CGen8OpenCLStateProcessor::CombineKernelBinary( const SStateProcessorContextGen8_0& context, const IGC::SOpenCLKernelInfo& annotations, const Util::BinaryStream& kernelHeap, const Util::BinaryStream& generalStateHeap, const Util::BinaryStream& dynamicStateHeap, const Util::BinaryStream& surfaceStateHeap, const Util::BinaryStream& patchList, unsigned int unpaddedBinarySize, Util::BinaryStream& kernelBinary ) { RETVAL retValue = g_cInitRetValue; iOpenCL::SKernelBinaryHeaderGen7 header; memset( &header, 0, sizeof( header ) ); header.ShaderHashCode = annotations.m_ShaderHashCode; header.KernelNameSize = (DWORD)annotations.m_kernelName.size() + 1; header.KernelNameSize += GetAlignmentOffset( header.KernelNameSize, sizeof(DWORD) ); header.PatchListSize = (DWORD)patchList.Size(); header.KernelHeapSize = (DWORD)kernelHeap.Size(); header.GeneralStateHeapSize = (DWORD)generalStateHeap.Size(); header.DynamicStateHeapSize = (DWORD)dynamicStateHeap.Size(); header.SurfaceStateHeapSize = (DWORD)surfaceStateHeap.Size(); header.KernelUnpaddedSize = (DWORD)unpaddedBinarySize; ICBE_DPF_STR( m_oclStateDebugMessagePrintOut, GFXDBG_HARDWARE, "Kernel Name: %s\n", annotations.m_kernelName.c_str() ); kernelBinary.Write( header ); kernelBinary.Write( annotations.m_kernelName.c_str(), annotations.m_kernelName.size() + 1 ); kernelBinary.Align( 4 ); kernelBinary.Write( kernelHeap ); kernelBinary.Write( generalStateHeap ); kernelBinary.Write( dynamicStateHeap ); kernelBinary.Write( surfaceStateHeap ); kernelBinary.Write( patchList ); IGC_ASSERT( IsAligned( kernelBinary.Size(), sizeof(DWORD) ) ); const char* pBuffer = kernelBinary.GetLinearPointer() + sizeof( iOpenCL::SKernelBinaryHeaderGen7 ); DWORD checkSumSize = (DWORD)kernelBinary.Size() - sizeof( iOpenCL::SKernelBinaryHeaderGen7 ); IGC_ASSERT( IsAligned( checkSumSize, sizeof(DWORD) ) ); QWORD hash = Hash( (const DWORD*) pBuffer, checkSumSize / sizeof(DWORD) ); header.CheckSum = hash & 0xFFFFFFFF; kernelBinary.WriteAt( header, 0 ); #if defined(_DEBUG) DWORD combinedBinarySize = header.KernelNameSize + header.KernelHeapSize + header.GeneralStateHeapSize + header.DynamicStateHeapSize + header.SurfaceStateHeapSize + header.PatchListSize; IGC_ASSERT( combinedBinarySize == checkSumSize ); const iOpenCL::SKernelBinaryHeaderGen7* pHeaderCheck = (const iOpenCL::SKernelBinaryHeaderGen7*)kernelBinary.GetLinearPointer(); IGC_ASSERT( pHeaderCheck->CheckSum == ( hash & 0xFFFFFFFF ) ); #endif if (IGC_IS_FLAG_ENABLED(DumpOCLProgramInfo)) { DebugKernelBinaryHeader_Gen7( &header, m_oclStateDebugMessagePrintOut); } return retValue; } RETVAL CGen8OpenCLStateProcessor::AddSamplerState( const bool enable, const SAMPLER_TEXTURE_ADDRESS_MODE& addressModeX, const SAMPLER_TEXTURE_ADDRESS_MODE& addressModeY, const SAMPLER_TEXTURE_ADDRESS_MODE& addressModeZ, const SAMPLER_MAPFILTER_TYPE& filterMag, const SAMPLER_MAPFILTER_TYPE& filterMin, const SAMPLER_MIPFILTER_TYPE& filterMip, const bool normalizedCoords, const SAMPLER_COMPARE_FUNC_TYPE& compareFunc, const DWORD borderColorOffset, Util::BinaryStream& membuf) { RETVAL retValue = g_cInitRetValue; if( retValue.Success ) { if (filterMag >= NUM_SAMPLER_MAPFILTER_TYPES || filterMin >= NUM_SAMPLER_MAPFILTER_TYPES || addressModeX >= NUM_SAMPLER_TEXTURE_ADDRESS_MODES || addressModeY >= NUM_SAMPLER_TEXTURE_ADDRESS_MODES || addressModeZ >= NUM_SAMPLER_TEXTURE_ADDRESS_MODES) { IGC_ASSERT(0); retValue.Success = false; } } if( retValue.Success ) { G6HWC::SSharedStateSamplerState samplerState = G6HWC::g_cInitSharedStateSamplerState; samplerState.DW0.Gen7 = G6HWC::g_cInitSharedStateSamplerStateDW0Gen7; samplerState.DW1.Gen7 = G6HWC::g_cInitSharedStateSamplerStateDW1Gen7; samplerState.DW3.Gen7 = G6HWC::g_cInitSharedStateSamplerStateDW3Gen7; if( enable ) { // Program client sampler state. samplerState.DW0.Gen7.MagModeFilter = g_cConvertSamplerMapFilter[filterMag]; samplerState.DW0.Gen7.MinModeFilter = g_cConvertSamplerMapFilter[filterMin]; samplerState.DW0.Gen7.MipModeFilter = g_cConvertSamplerMipFilter[filterMip]; samplerState.DW1.Gen7.MinLOD = 0; samplerState.DW1.Gen7.MaxLOD = FloatToFixed( HWCaps().SampleLOD.Max, 4, 8 ); samplerState.DW2.Gen8.All.IndirectStatePointer = borderColorOffset / HWCaps().DefaultColorPointerAlignSize; samplerState.DW3.Gen7.TCXAddressControlMode = g_cConvertSamplerTextureAddressMode[addressModeX]; samplerState.DW3.Gen7.TCYAddressControlMode = g_cConvertSamplerTextureAddressMode[addressModeY]; samplerState.DW3.Gen7.TCZAddressControlMode = g_cConvertSamplerTextureAddressMode[addressModeZ]; samplerState.DW3.Gen7.NonNormalizedCoordinateEnable = !normalizedCoords; // Program additional sampler state. samplerState.DW0.Gen7.SamplerDisable = false; if( filterMag != SAMPLER_MAPFILTER_POINT ) { samplerState.DW3.Gen7.UAddressMagFilterAddressRoundingEnable = true; samplerState.DW3.Gen7.VAddressMagFilterAddressRoundingEnable = true; samplerState.DW3.Gen7.RAddressMagFilterAddressRoundingEnable = true; } if (filterMin != SAMPLER_MAPFILTER_POINT) { samplerState.DW3.Gen7.UAddressMinFilterAddressRoundingEnable = true; samplerState.DW3.Gen7.VAddressMinFilterAddressRoundingEnable = true; samplerState.DW3.Gen7.RAddressMinFilterAddressRoundingEnable = true; } samplerState.DW1.Gen7.ShadowFunction = g_cConvertCompareFunc[compareFunc]; } else { samplerState.DW0.Gen7.SamplerDisable = true; } if( membuf.Write( samplerState ) == false ) { retValue.Success = false; IGC_ASSERT(0); } #if ( defined( _DEBUG ) || defined( _INTERNAL ) || defined( _RELEASE_INTERNAL ) ) { G6HWC::DebugSamplerStateCommand( &samplerState, m_Platform, m_oclStateDebugMessagePrintOut ); } #endif } return retValue; } RETVAL CGen8OpenCLStateProcessor::AddSurfaceState( const SURFACE_TYPE& type, const SURFACE_FORMAT& surfaceFormat, const DWORD bufferLength, bool isMultiSampleImage, Util::BinaryStream& membuf ) { RETVAL retValue = g_cInitRetValue; if( retValue.Success ) { G6HWC::SSharedStateSurfaceState surf = G6HWC::g_cInitSharedStateSurfaceState; surf.DW0.Gen8 = G6HWC::g_cInitSharedStateSurfaceStateDW0Gen8; surf.DW1.Gen8 = G6HWC::g_cInitSharedStateSurfaceStateDW1Gen8; surf.DW2.Gen7 = G6HWC::g_cInitSharedStateSurfaceStateDW2Gen7; surf.DW3.Gen7 = G6HWC::g_cInitSharedStateSurfaceStateDW3Gen7; surf.DW4.Gen7 = G6HWC::g_cInitSharedStateSurfaceStateDW4Gen7; surf.DW5.Gen8 = G6HWC::g_cInitSharedStateSurfaceStateDW5Gen8; surf.DW6.Gen7.SurfaceMCS = G6HWC::g_cInitSharedStateSurfaceStateDW6MCSGen7; surf.DW7.Gen7 = G6HWC::g_cInitSharedStateSurfaceStateDW7Gen7; surf.DW8.Gen8 = G6HWC::g_cInitSharedStateSurfaceStateDW8Gen8; surf.DW9.Gen8 = G6HWC::g_cInitSharedStateSurfaceStateDW9Gen8; surf.DW10.Gen8 = G6HWC::g_cInitSharedStateSurfaceStateDW10Gen8; surf.DW11.Gen8 = G6HWC::g_cInitSharedStateSurfaceStateDW11Gen8; surf.DW12.Gen8 = G6HWC::g_cInitSharedStateSurfaceStateDW12Gen8; surf.DW0.Gen8.TileMode = G6HWC::GFXSHAREDSTATE_TILEMODE_LINEAR; if( type != SURFACE_UNKNOWN ) { surf.DW0.Gen8.SurfaceType = g_cConvertSurfaceType[ type ]; if( type == SURFACE_BUFFER ) { G6HWC::SSurfaceStateBufferLength ssbl = G6HWC::g_cInitSurfaceStateBufferLength; ssbl.Length = bufferLength - 1; surf.DW0.Gen8.SurfaceFormat = g_cConvertSurfaceFormat[ surfaceFormat ]; surf.DW2.Gen7.Height = ssbl.All.Height; surf.DW2.Gen7.Width = ssbl.All.Width; surf.DW3.Gen7.Depth = ssbl.All.Depth; } else if( ( type == SURFACE_1D_ARRAY ) || ( type == SURFACE_2D_ARRAY ) ) { surf.DW0.Gen7.SurfaceArray = true; } surf.DW4.Gen7.SurfaceAll.MultisampledSurfaceStorageFormat = isMultiSampleImage; } G6HWC::DebugSurfaceStateCommand( &surf, m_Platform, m_oclStateDebugMessagePrintOut ); if( membuf.Write( surf ) == false ) { IGC_ASSERT(0); retValue.Success = false; } } return retValue; } bool CGen8OpenCLStateProcessor::InlineSamplersAllow3DImageTransformation(const IGC::SOpenCLKernelInfo& annotations) const { // To be transformable, we need inline samplers to have: // addressMode == CLAMP_TO_EDGE // filter == NEAREST // normalizedCoords = false for (auto i = annotations.m_samplerInput.begin(); i != annotations.m_samplerInput.end(); ++i) { const SamplerInputAnnotation* samplerAnnotation = *i; if (samplerAnnotation->SamplerType == SAMPLER_OBJECT_TEXTURE) { if (samplerAnnotation->NormalizedCoords || samplerAnnotation->TCXAddressMode != SAMPLER_TEXTURE_ADDRESS_MODE_CLAMP || samplerAnnotation->TCYAddressMode != SAMPLER_TEXTURE_ADDRESS_MODE_CLAMP || samplerAnnotation->TCZAddressMode != SAMPLER_TEXTURE_ADDRESS_MODE_CLAMP || samplerAnnotation->MagFilterType != SAMPLER_MAPFILTER_POINT || samplerAnnotation->MinFilterType != SAMPLER_MAPFILTER_POINT) { return false; } } } return true; } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/sp_g8.h000066400000000000000000000205061363533017100240220ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #include "../Platform/cmd_media_caps_g8.h" #include "../../inc/common/igfxfmid.h" #include "../CommandStream/SamplerTypes.h" #include "../CommandStream/SurfaceTypes.h" #include "../KernelAnnotations.hpp" #include "../util/BinaryStream.h" #include "../Patch/patch_parser.h" #include "inc/common/Compiler/API/SurfaceFormats.h" #include "usc.h" #include "sp_debug.h" #include "Probe.h" namespace IGC { struct SOpenCLKernelInfo; struct SOpenCLProgramInfo; class CBTILayout; class OpenCLProgramContext; } namespace G6HWC { struct SGfxSamplerIndirectState; } namespace iOpenCL { // Forward Declare struct SStateProcessorContextGen8_0; struct RETVAL { DWORD Success; }; extern RETVAL g_cInitRetValue; class DisallowCopy { public: DisallowCopy() { }; virtual ~DisallowCopy() {}; private: DisallowCopy( const DisallowCopy& ); DisallowCopy& operator=(const DisallowCopy&); }; class CGen8OpenCLStateProcessor : DisallowCopy { public: explicit CGen8OpenCLStateProcessor(PLATFORM platform); virtual ~CGen8OpenCLStateProcessor( void ); virtual void CreateKernelBinary( const char* rawIsaBinary, unsigned int rawIsaBinarySize, const IGC::SOpenCLKernelInfo& annotations, const IGC::SOpenCLProgramInfo& programInfo, const IGC::CBTILayout& layout, Util::BinaryStream& kernelHeap, USC::SSystemThreadKernelOutput* pSystemThreadKernelOutput, unsigned int unpaddedBinarySize); void CreateProgramScopePatchStream(const IGC::SOpenCLProgramInfo& annotations, Util::BinaryStream& membuf); virtual void CreateKernelDebugData( const char* rawDebugDataVISA, unsigned int rawDebugDataVISASize, const char* rawDebugDataGenISA, unsigned int rawDebugDataGenISASize, const std::string& kernelName, Util::BinaryStream& kernelDebugData); // Optional OpeneCL program context. const IGC::OpenCLProgramContext *m_Context = nullptr; std::string m_oclStateDebugMessagePrintOut; private: const G6HWC::SMediaHardwareCapabilities& HWCaps() const; RETVAL AddSystemKernel( const USC::SSystemThreadKernelOutput* pSystemThreadKernelOutput, SStateProcessorContextGen8_0& context, Util::BinaryStream& membuf); RETVAL CreateKernelHeap( const IGC::SOpenCLKernelInfo& annotations, const char* kernelBinary, unsigned int kernelBinarySize, USC::SSystemThreadKernelOutput* pSystemThreadKernelOutput, SStateProcessorContextGen8_0& context, Util::BinaryStream& membuf ); RETVAL CreateSurfaceStateHeap( const IGC::SOpenCLKernelInfo& annotations, const IGC::CBTILayout& layout, const bool gtpinEnabled, SStateProcessorContextGen8_0& context, Util::BinaryStream& ); RETVAL CreateDynamicStateHeap( const IGC::SOpenCLKernelInfo& annotations, SStateProcessorContextGen8_0& context, Util::BinaryStream& ); RETVAL CreateGeneralStateHeap( const IGC::SOpenCLKernelInfo& annotations, SStateProcessorContextGen8_0& context, Util::BinaryStream& ); RETVAL CreatePatchList( const IGC::SOpenCLKernelInfo& annotations, const IGC::SOpenCLProgramInfo& programInfo, const IGC::CBTILayout& layout, const SStateProcessorContextGen8_0& context, const bool gtpinEnabled, Util::BinaryStream& ); RETVAL CombineKernelBinary( const SStateProcessorContextGen8_0& context, const IGC::SOpenCLKernelInfo& annotations, const Util::BinaryStream& kernelHeap, const Util::BinaryStream& generalStateHeap, const Util::BinaryStream& dynamicStateHeap, const Util::BinaryStream& surfaceStateHeap, const Util::BinaryStream& patchListHeap, unsigned int unpaddedBinarySize, Util::BinaryStream& kernelBinary ); template RETVAL AddPatchItem( PatchType& patch, Util::BinaryStream& membuf ) { RETVAL retValue = g_cInitRetValue; if( membuf.Write( patch ) == false ) { retValue.Success = false; } #if defined(_DEBUG) || defined(_INTERNAL) || defined(_RELEASE_INTERNAL) DebugPatchList(&patch, patch.Size, m_oclStateDebugMessagePrintOut); #endif return retValue; } RETVAL AddSamplerState( const bool enable, const SAMPLER_TEXTURE_ADDRESS_MODE& addressModeX, const SAMPLER_TEXTURE_ADDRESS_MODE& addressModeY, const SAMPLER_TEXTURE_ADDRESS_MODE& addressModeZ, const SAMPLER_MAPFILTER_TYPE& filterMag, const SAMPLER_MAPFILTER_TYPE& filterMin, const SAMPLER_MIPFILTER_TYPE& filterMip, const bool normalizedCoords, const SAMPLER_COMPARE_FUNC_TYPE& compareFunc, const DWORD borderColorOffset, Util::BinaryStream& membuf ); DWORD AllocateSamplerIndirectState( const G6HWC::SGfxSamplerIndirectState& borderColor, Util::BinaryStream &membuf); RETVAL AddSurfaceState( const SURFACE_TYPE& type, const IGC::SURFACE_FORMAT& surfaceFormat, const DWORD bufferLength, bool isMultiSampleImage, Util::BinaryStream& membuf ); RETVAL AddKernelAttributePatchItems( const IGC::SOpenCLKernelInfo& annotations, Util::BinaryStream& membuf ); RETVAL AddKernelArgumentPatchItems( const IGC::SOpenCLKernelInfo& annotations, Util::BinaryStream& membuf ); RETVAL AddStringPatchItem( const std::string& str, Util::BinaryStream& membuf, uint32_t& bytesWritten ) const; inline DWORD GetSamplerStateSizeMultiplier( const SAMPLER_OBJECT_TYPE samplerType ) const; /// Returns TRUE if the samplers allow 3D images to be represented as arrays of 2D images. bool InlineSamplersAllow3DImageTransformation( const IGC::SOpenCLKernelInfo& annotations) const; // State G6HWC::SMediaHardwareCapabilities m_HWCaps; PLATFORM m_Platform; // Constants enum { DEFAULT_CONSTANT_BUFFER_INDEX = 0} ; }; inline DWORD CGen8OpenCLStateProcessor::GetSamplerStateSizeMultiplier( const SAMPLER_OBJECT_TYPE samplerType ) const { DWORD multiplier = 0; switch( samplerType ) { case SAMPLER_OBJECT_TEXTURE: multiplier = 1; break; case SAMPLER_OBJECT_VME: multiplier = 8; break; case SAMPLER_OBJECT_SAMPLE_8X8_ERODE: multiplier = 2; break; case SAMPLER_OBJECT_SAMPLE_8X8_DILATE: multiplier = 2; break; case SAMPLER_OBJECT_SAMPLE_8X8_MINMAXFILTER: multiplier = 2; break; case SAMPLER_OBJECT_SAMPLE_8X8_2DCONVOLVE: multiplier = 128; break; case SAMPLER_OBJECT_SAMPLE_8X8_MINMAX: multiplier = 0; break; case SAMPLER_OBJECT_SAMPLE_8X8_CENTROID: multiplier = 0; break; case SAMPLER_OBJECT_SAMPLE_8X8_BOOL_CENTROID: multiplier = 0; break; case SAMPLER_OBJECT_SAMPLE_8X8_BOOL_SUM: multiplier = 0; break; default: IGC_ASSERT(0 && "Unknown sampler type"); multiplier = 0; break; } return multiplier; } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/sp_types.h000066400000000000000000000072011363533017100246450ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #if defined(_WIN32) typedef unsigned __int64 QWORD; // 64-bits, 8-bytes typedef unsigned long DWORD; // 32-bits, 4-bytes typedef signed __int64 INT64; // 64-bits, 8-bytes typedef unsigned __int64 UINT64; // 64-bits, 8-bytes typedef unsigned long ULONG; // 32-bits, 4-bytes #else // if !defined(_WIN32) typedef std::uint64_t QWORD; // 64-bits, 8-bytes typedef std::uint32_t DWORD; // 32-bits, 4-bytes typedef std::int64_t INT64; // 64-bits, 8-bytes typedef std::uint64_t UINT64; // 64-bits, 8-bytes typedef unsigned int ULONG; #endif typedef unsigned int UINT32; // 32-bits, 4-bytes typedef unsigned int UINT; // 32-bits, 4-bytes typedef int INT; // 32-bits, 4-bytes typedef unsigned char BYTE; // 8-bits, 1-byte typedef unsigned short WORD; // 16-bits, 2-bytes typedef BYTE KILOBYTE[1024]; // 1024-bytes typedef KILOBYTE MEGABYTE[1024]; // 1024-kilobytes typedef MEGABYTE GIGABYTE[1024]; // 1024-megabytes typedef BYTE PAGE[4096]; // 4096-bytes typedef unsigned short HEXWORD[16]; // 256-bits, 32-bytes /*****************************************************************************\ MACRO: BITFIELD_RANGE PURPOSE: Calculates the number of bits between the startbit and the endbit (0 based) \*****************************************************************************/ #ifndef BITFIELD_RANGE #define BITFIELD_RANGE( startbit, endbit ) ((endbit)-(startbit)+1) #endif /*****************************************************************************\ MACRO: BITFIELD_BIT PURPOSE: Definition declared for clarity when creating structs \*****************************************************************************/ #ifndef BITFIELD_BIT #define BITFIELD_BIT( bit ) 1 #endif /*****************************************************************************\ MACRO: SIZE32 \*****************************************************************************/ #ifndef SIZE32 #define SIZE32( x ) ((DWORD)( sizeof(x) / sizeof(DWORD) )) #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/spp_g8.cpp000066400000000000000000000242741363533017100245430ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "spp_g8.h" #include "../../../Compiler/CodeGenPublic.h" #include "program_debug_data.h" #include "../../../common/Types.hpp" #include "../../../common/shaderOverride.hpp" #include "../../../Compiler/CISACodeGen/OpenCLKernelCodeGen.hpp" #include "cmc.h" #include #include #include "Probe.h" namespace iOpenCL { extern RETVAL g_cInitRetValue; CGen8OpenCLProgramBase::CGen8OpenCLProgramBase(PLATFORM platform) : m_Platform(platform) , m_StateProcessor(platform) { m_ProgramScopePatchStream = new Util::BinaryStream; } CGen8OpenCLProgramBase::~CGen8OpenCLProgramBase() { delete m_ProgramScopePatchStream; for (auto data : m_KernelBinaries) { delete data.kernelBinary; delete data.kernelDebugData; } delete m_pSystemThreadKernelOutput; m_pSystemThreadKernelOutput = nullptr; } RETVAL CGen8OpenCLProgramBase::GetProgramBinary( Util::BinaryStream& programBinary, unsigned pointerSizeInBytes ) { RETVAL retValue = g_cInitRetValue; iOpenCL::SProgramBinaryHeader header; memset( &header, 0, sizeof( header ) ); header.Magic = iOpenCL::MAGIC_CL; header.Version = iOpenCL::CURRENT_ICBE_VERSION; header.Device = m_Platform.eRenderCoreFamily; header.GPUPointerSizeInBytes = pointerSizeInBytes; header.NumberOfKernels = m_KernelBinaries.size(); header.SteppingId = m_Platform.usRevId; header.PatchListSize = int_cast(m_ProgramScopePatchStream->Size()); if (IGC_IS_FLAG_ENABLED(DumpOCLProgramInfo)) { DebugProgramBinaryHeader(&header, m_StateProcessor.m_oclStateDebugMessagePrintOut); } programBinary.Write( header ); programBinary.Write( *m_ProgramScopePatchStream ); for( auto data : m_KernelBinaries ) { programBinary.Write( *(data.kernelBinary) ); } return retValue; } void CGen8OpenCLProgramBase::CreateProgramScopePatchStream(const IGC::SOpenCLProgramInfo& annotations) { m_StateProcessor.CreateProgramScopePatchStream(annotations, *m_ProgramScopePatchStream); } CGen8OpenCLProgram::CGen8OpenCLProgram(PLATFORM platform, IGC::OpenCLProgramContext& context) : CGen8OpenCLProgramBase(platform) , m_pContext(&context) { m_StateProcessor.m_Context = &context; } CGen8OpenCLProgram::~CGen8OpenCLProgram() { for (auto p : m_ShaderProgramList) { delete p; } m_ShaderProgramList.clear(); } RETVAL CGen8OpenCLProgramBase::GetProgramDebugData(Util::BinaryStream& programDebugData) { RETVAL retValue = g_cInitRetValue; unsigned numDebugBinaries = 0; for (auto data : m_KernelBinaries) { if (data.kernelDebugData && data.kernelDebugData->Size() > 0) { numDebugBinaries++; } } if( numDebugBinaries ) { iOpenCL::SProgramDebugDataHeaderIGC header; memset( &header, 0, sizeof( header ) ); header.Magic = iOpenCL::MAGIC_CL; header.Version = iOpenCL::CURRENT_ICBE_VERSION; header.Device = m_Platform.eRenderCoreFamily; header.NumberOfKernels = numDebugBinaries; header.SteppingId = m_Platform.usRevId; programDebugData.Write( header ); for (auto data : m_KernelBinaries) { if (data.kernelDebugData && data.kernelDebugData->Size() > 0) { programDebugData.Write( *(data.kernelDebugData) ); } } } return retValue; } void dumpOCLKernelBinary( const IGC::COpenCLKernel *Kernel, const KernelData &data) { #if LLVM_VERSION_MAJOR >= 7 using namespace IGC; using namespace IGC::Debug; auto *Ctx = Kernel->GetContext(); auto &kernelName = Kernel->m_kernelInfo.m_kernelName; auto name = DumpName(IGC::Debug::GetShaderOutputName()) .Hash(Ctx->hash) .Type(ShaderType::OPENCL_SHADER) .PostFix(kernelName) .Extension("kernbin"); auto *KernBin = data.kernelBinary; std::error_code EC; llvm::raw_fd_ostream f(name.str(), EC); if (!EC) f.write(KernBin->GetLinearPointer(), (size_t)KernBin->Size()); #endif } void overrideOCLKernelBinary( const IGC::COpenCLKernel *Kernel, KernelData &data) { using namespace IGC; using namespace IGC::Debug; auto *Ctx = Kernel->GetContext(); auto &kernelName = Kernel->m_kernelInfo.m_kernelName; auto name = DumpName(IGC::Debug::GetShaderOutputName()) .Hash(Ctx->hash) .Type(ShaderType::OPENCL_SHADER) .PostFix(kernelName) .Extension("kernbin"); std::string Path = name.overridePath(); std::ifstream f(Path, std::ios::binary); if (!f.is_open()) return; appendToShaderOverrideLogFile(Path, "OVERRIDDEN: "); f.seekg(0, f.end); int newBinarySize = (int)f.tellg(); f.seekg(0, f.beg); auto *&KernBin = data.kernelBinary; delete KernBin; KernBin = new Util::BinaryStream(); std::unique_ptr Buf(new char[newBinarySize]); f.read(Buf.get(), newBinarySize); IGC_ASSERT(f && "Not fully read!"); KernBin->Write(Buf.get(), newBinarySize); } void CGen8OpenCLProgram::CreateKernelBinaries() { auto isValidShader = [&](IGC::COpenCLKernel* shader)->bool { return (shader && shader->ProgramOutput()->m_programSize > 0); }; for (auto pKernel : m_ShaderProgramList) { IGC::COpenCLKernel* simd8Shader = static_cast(pKernel->GetShader(SIMDMode::SIMD8)); IGC::COpenCLKernel* simd16Shader = static_cast(pKernel->GetShader(SIMDMode::SIMD16)); IGC::COpenCLKernel* simd32Shader = static_cast(pKernel->GetShader(SIMDMode::SIMD32)); // Determine how many simd modes we have per kernel std::vector kernelVec; if (m_pContext->m_DriverInfo.sendMultipleSIMDModes() && (m_pContext->getModuleMetaData()->csInfo.forcedSIMDSize == 0)) { // For multiple SIMD modes, send SIMD modes in descending order if (isValidShader(simd32Shader)) kernelVec.push_back(simd32Shader); if (isValidShader(simd16Shader)) kernelVec.push_back(simd16Shader); if (isValidShader(simd8Shader)) kernelVec.push_back(simd8Shader); } else { if (isValidShader(simd32Shader)) kernelVec.push_back(simd32Shader); else if (isValidShader(simd16Shader)) kernelVec.push_back(simd16Shader); else if (isValidShader(simd8Shader)) kernelVec.push_back(simd8Shader); } for (auto kernel : kernelVec) { IGC::SProgramOutput* pOutput = kernel->ProgramOutput(); // Create the kernel binary streams KernelData data; data.kernelBinary = new Util::BinaryStream(); m_StateProcessor.CreateKernelBinary( (const char*)pOutput->m_programBin, pOutput->m_programSize, kernel->m_kernelInfo, m_pContext->m_programInfo, m_pContext->btiLayout, *(data.kernelBinary), m_pSystemThreadKernelOutput, pOutput->m_unpaddedProgramSize); if (IGC_IS_FLAG_ENABLED(ShaderDumpEnable)) dumpOCLKernelBinary(kernel, data); if (IGC_IS_FLAG_ENABLED(ShaderOverride)) overrideOCLKernelBinary(kernel, data); IGC_ASSERT(data.kernelBinary && data.kernelBinary->Size() > 0); // Create the debug data binary streams if (pOutput->m_debugDataVISASize > 0 || pOutput->m_debugDataGenISASize > 0) { data.kernelDebugData = new Util::BinaryStream(); m_StateProcessor.CreateKernelDebugData( (const char*)pOutput->m_debugDataVISA, pOutput->m_debugDataVISASize, (const char*)pOutput->m_debugDataGenISA, pOutput->m_debugDataGenISASize, kernel->m_kernelInfo.m_kernelName, *(data.kernelDebugData)); } m_KernelBinaries.push_back(data); } } } // Implementation of CGen8CMProgram. CGen8CMProgram::CGen8CMProgram(PLATFORM platform) : CGen8OpenCLProgramBase(platform) , m_programInfo(new IGC::SOpenCLProgramInfo) { } CGen8CMProgram::~CGen8CMProgram() { for (auto kernel : m_kernels) delete kernel; } void CGen8CMProgram::CreateKernelBinaries() { for (auto kernel : m_kernels) { // Create the kernel binary streams. KernelData data; data.kernelBinary = new Util::BinaryStream; m_StateProcessor.CreateKernelBinary( (const char*)kernel->m_prog.m_programBin, kernel->m_prog.m_programSize, kernel->m_kernelInfo, *m_programInfo, kernel->m_btiLayout, *(data.kernelBinary), m_pSystemThreadKernelOutput, kernel->m_prog.m_unpaddedProgramSize); m_KernelBinaries.push_back(data); } } } // namespace iOpenCL intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/sp/spp_g8.h000066400000000000000000000065351363533017100242100ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #include "../util/BinaryStream.h" #include "usc.h" #include "sp_g8.h" namespace IGC { class OpenCLProgramContext; class CShaderProgram; class COCLBTILayout; struct SOpenCLProgramInfo; struct SProgramOutput; }; namespace cmc { class CMKernel; }; namespace iOpenCL { struct KernelData { Util::BinaryStream* kernelBinary = nullptr; Util::BinaryStream* kernelDebugData = nullptr; }; // This is the base class to create an OpenCL ELF binary with patch tokens. // It owns BinaryStreams allocated. class CGen8OpenCLProgramBase : DisallowCopy { public: explicit CGen8OpenCLProgramBase(PLATFORM platform); virtual ~CGen8OpenCLProgramBase(); RETVAL GetProgramBinary(Util::BinaryStream& programBinary, unsigned pointerSizeInBytes); RETVAL GetProgramDebugData(Util::BinaryStream& programDebugData); void CreateProgramScopePatchStream(const IGC::SOpenCLProgramInfo& programInfo); // Used to store per-kernel binary streams and kernelInfo std::vector m_KernelBinaries; USC::SSystemThreadKernelOutput* m_pSystemThreadKernelOutput = nullptr; PLATFORM getPlatform() const { return m_Platform; } protected: PLATFORM m_Platform; CGen8OpenCLStateProcessor m_StateProcessor; Util::BinaryStream* m_ProgramScopePatchStream = nullptr; }; class CGen8OpenCLProgram : public CGen8OpenCLProgramBase { public: CGen8OpenCLProgram(PLATFORM platform, IGC::OpenCLProgramContext &context); ~CGen8OpenCLProgram(); void CreateKernelBinaries(); // Used to track the kernel info from CodeGen std::vector m_ShaderProgramList; private: IGC::OpenCLProgramContext* m_pContext = nullptr; }; class CGen8CMProgram : public CGen8OpenCLProgramBase { public: explicit CGen8CMProgram(PLATFORM platform); ~CGen8CMProgram(); // Produce the final ELF binary with the given CM kernels // in OpenCL format. void CreateKernelBinaries(); // CM kernel list. std::vector m_kernels; // Data structure to create patch token based binaries. std::unique_ptr m_programInfo; }; } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/util/000077500000000000000000000000001363533017100231615ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/util/BinaryStream.cpp000066400000000000000000000072031363533017100262670ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "BinaryStream.h" namespace Util { BinaryStream::BinaryStream() : m_membuf( std::ios::in | std::ios::out | std::ios::binary ) { // Nothing! } BinaryStream::~BinaryStream() { // Nothing! } bool BinaryStream::Write( const char* s, std::streamsize n ) { bool retValue = false; std::streamsize prevSize = Size(); m_membuf.write( s, n ); if( ( Size() - prevSize ) == n ) { retValue = true; } if( m_membuf.fail() ) { retValue = false; } #if defined(_DEBUG) GetLinearPointer(); #endif return retValue; } bool BinaryStream::Write( const BinaryStream& in ) { bool retValue = false; std::streamsize prevSize = Size(); m_membuf << in.m_membuf.str(); if( ( Size() - prevSize ) == in.Size() ) { retValue = true; } if( m_membuf.fail() ) { retValue = false; } #if defined(_DEBUG) GetLinearPointer(); #endif return retValue; } bool BinaryStream::WriteAt( const char* s, std::streamsize n, std::streamsize loc ) { bool retValue = true; // Give this function name it seems like this function should enlarge the stream if needed. Discuss. if( ( n + loc ) < Size() ) { m_membuf.seekp( loc, std::ios_base::beg ); Write( s, n ); m_membuf.seekp( 0, std::ios_base::end ); } else { retValue = false; } return retValue; } const char* BinaryStream::GetLinearPointer() { m_LinearPointer = m_membuf.str(); return m_LinearPointer.c_str(); } bool BinaryStream::Align( std::streamsize alignment ) { bool retValue = true; std::streamsize currentSize = Size(); std::streamsize modulo = currentSize % alignment; if( modulo ) { std::streamsize offset = alignment - modulo; retValue = AddPadding( offset ); } retValue &= ( Size() % alignment ) == 0; return retValue; } bool BinaryStream::AddPadding( std::streamsize padding ) { bool retValue = true; while( padding-- ) { // Always pad with 0x0 to make external tools that parse // OpenCL program binaries easier to maintain retValue &= Write( (char)0x0 ); } return retValue; } std::streamsize BinaryStream::Size() const { // tellp is a non const function // TODO: Is there a better way to do this? return const_cast(this)->Size(); } std::streamsize BinaryStream::Size() { return m_membuf.tellp(); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/OCL/util/BinaryStream.h000066400000000000000000000040661363533017100257400ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include namespace Util { class BinaryStream { public: BinaryStream(); ~BinaryStream(); bool Write( const char* s, std::streamsize n ); bool Write( const BinaryStream& in ); template< class T > bool Write( const T& in ); bool WriteAt( const char* s, std::streamsize n, std::streamsize loc ); template< class T > bool WriteAt( const T& in, std::streamsize loc ) { return WriteAt( (const char*)&in, sizeof(T), loc ); } bool Align( std::streamsize alignment ); bool AddPadding( std::streamsize padding ); const char* GetLinearPointer(); std::streamsize Size() const; std::streamsize Size(); private: std::stringstream m_membuf; std::string m_LinearPointer; }; template< class T > bool BinaryStream::Write(const T& in ) { return Write( (const char*)&in, sizeof(T) ); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/PatchList.h000066400000000000000000000026451363533017100236420ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once // PatchList.h will be removed after change propagation to Metal. Please make // all changes in ocl_igc_interface/executable_format/patch_list.h #include "ocl_igc_shared/executable_format/patch_list.h" intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/000077500000000000000000000000001363533017100224725ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/Mangler/000077500000000000000000000000001363533017100240575ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/Mangler/ParameterType.h000066400000000000000000000355051363533017100270220ustar00rootroot00000000000000//===------------------------- ParameterType.h ---------------------------===// // // SPIR Tools // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// /* * Contributed by: Intel Corporation. */ #ifndef __PARAMETER_TYPE_H__ #define __PARAMETER_TYPE_H__ #include "Refcount.h" #include #include #include "Probe.h" // The Type class hierarchy models the different types in OCL. namespace SPIR { // Supported SPIR versions enum SPIRversion { SPIR12 = 1, SPIR20 = 2 }; // Error Status values enum MangleError { MANGLE_SUCCESS, MANGLE_TYPE_NOT_SUPPORTED, MANGLE_NULL_FUNC_DESCRIPTOR }; enum TypePrimitiveEnum { PRIMITIVE_FIRST, PRIMITIVE_BOOL = PRIMITIVE_FIRST, PRIMITIVE_UCHAR, PRIMITIVE_CHAR, PRIMITIVE_USHORT, PRIMITIVE_SHORT, PRIMITIVE_UINT, PRIMITIVE_INT, PRIMITIVE_ULONG, PRIMITIVE_LONG, PRIMITIVE_HALF, PRIMITIVE_FLOAT, PRIMITIVE_DOUBLE, PRIMITIVE_VOID, PRIMITIVE_VAR_ARG, PRIMITIVE_STRUCT_FIRST, PRIMITIVE_IMAGE_1D_T = PRIMITIVE_STRUCT_FIRST, PRIMITIVE_IMAGE_1D_ARRAY_T, PRIMITIVE_IMAGE_1D_BUFFER_T, PRIMITIVE_IMAGE_2D_T, PRIMITIVE_IMAGE_2D_ARRAY_T, PRIMITIVE_IMAGE_3D_T, PRIMITIVE_IMAGE_2D_MSAA_T, PRIMITIVE_IMAGE_2D_ARRAY_MSAA_T, PRIMITIVE_IMAGE_2D_MSAA_DEPTH_T, PRIMITIVE_IMAGE_2D_ARRAY_MSAA_DEPTH_T, PRIMITIVE_IMAGE_2D_DEPTH_T, PRIMITIVE_IMAGE_2D_ARRAY_DEPTH_T, PRIMITIVE_EVENT_T, PRIMITIVE_PIPE_T, PRIMITIVE_RESERVE_ID_T, PRIMITIVE_QUEUE_T, PRIMITIVE_NDRANGE_T, PRIMITIVE_CLK_EVENT_T, PRIMITIVE_STRUCT_LAST = PRIMITIVE_CLK_EVENT_T, PRIMITIVE_SAMPLER_T, PRIMITIVE_KERNEL_ENQUEUE_FLAGS_T, PRIMITIVE_CLK_PROFILING_INFO, PRIMITIVE_LAST = PRIMITIVE_CLK_PROFILING_INFO, PRIMITIVE_NONE, // Keep this at the end. PRIMITIVE_NUM = PRIMITIVE_NONE }; enum TypeEnum { TYPE_ID_PRIMITIVE, TYPE_ID_POINTER, TYPE_ID_VECTOR, TYPE_ID_ATOMIC, TYPE_ID_BLOCK, TYPE_ID_STRUCTURE }; enum TypeAttributeEnum { ATTR_QUALIFIER_FIRST = 0, ATTR_RESTRICT = ATTR_QUALIFIER_FIRST, ATTR_VOLATILE, ATTR_CONST, ATTR_QUALIFIER_LAST = ATTR_CONST, ATTR_ADDR_SPACE_FIRST, ATTR_PRIVATE = ATTR_ADDR_SPACE_FIRST, ATTR_GLOBAL, ATTR_CONSTANT, ATTR_LOCAL, ATTR_GENERIC, ATTR_ADDR_SPACE_LAST = ATTR_GENERIC, ATTR_NONE, ATTR_NUM = ATTR_NONE }; // Forward declaration for abstract structure. struct ParamType; typedef RefCount RefParamType; // Forward declaration for abstract structure. struct TypeVisitor; struct ParamType { /// @brief Constructor. /// @param TypeEnum type id. ParamType(TypeEnum typeId) : m_typeId(typeId) {}; /// @brief Destructor. virtual ~ParamType() {}; /// Abstract Methods /// /// @brief Visitor service method. (see TypeVisitor for more details). /// When overridden in subclasses, preform a 'double dispatch' to the /// appropriate visit method in the given visitor. /// @param TypeVisitor type visitor. virtual MangleError accept(TypeVisitor*) const = 0; /// @brief Returns a string representation of the underlying type. /// @return type as string. virtual std::string toString() const = 0; /// @brief Returns true if given param type is equal to this type. /// @param ParamType given param type. /// @return true if given param type is equal to this type and false otherwise. virtual bool equals(const ParamType*) const = 0; /// Common Base-Class Methods /// /// @brief Returns type id of underlying type. /// @return type id. TypeEnum getTypeId() const { return m_typeId; } private: // @brief Default Constructor. ParamType(); protected: /// An enumeration to identify the type id of this instance. TypeEnum m_typeId; }; struct PrimitiveType : public ParamType { /// An enumeration to identify the type id of this class. const static TypeEnum enumTy; /// @brief Constructor. /// @param TypePrimitiveEnum primitive id. PrimitiveType(TypePrimitiveEnum); /// Implementation of Abstract Methods /// /// @brief Visitor service method. (see TypeVisitor for more details). /// When overridden in subclasses, preform a 'double dispatch' to the /// appropriate visit method in the given visitor. /// @param TypeVisitor type visitor. MangleError accept(TypeVisitor*) const; /// @brief Returns a string representation of the underlying type. /// @return type as string. std::string toString() const; /// @brief Returns true if given param type is equal to this type. /// @param ParamType given param type. /// @return true if given param type is equal to this type and false otherwise. bool equals(const ParamType*) const; /// Non-Common Methods /// /// @brief Returns the primitive enumeration of the type. /// @return primitive type. TypePrimitiveEnum getPrimitive() const { return m_primitive; } protected: /// An enumeration to identify the primitive type. TypePrimitiveEnum m_primitive; }; struct PointerType: public ParamType { /// An enumeration to identify the type id of this class. const static TypeEnum enumTy; /// @brief Constructor. /// @param RefParamType the type of pointee (that the pointer points at). PointerType(const RefParamType type); /// Implementation of Abstract Methods /// /// @brief Visitor service method. (see TypeVisitor for more details). /// When overridden in subclasses, preform a 'double dispatch' to the /// appropriate visit method in the given visitor. /// @param TypeVisitor type visitor MangleError accept(TypeVisitor*) const; /// @brief Returns a string representation of the underlying type. /// @return type as string. std::string toString() const; /// @brief Returns true if given param type is equal to this type. /// @param ParamType given param type. /// @return true if given param type is equal to this type and false otherwise. bool equals(const ParamType*) const; /// Non-Common Methods /// /// @brief Returns the type the pointer is pointing at. /// @return pointee type. const RefParamType& getPointee() const { return m_pType; } /// @brief Sets the address space attribute - default is __private /// @param TypeAttributeEnum address space attribute id. void setAddressSpace(TypeAttributeEnum attr); /// @brief Returns the pointer's address space. /// @return pointer's address space. TypeAttributeEnum getAddressSpace() const; /// @brief Adds or removes a pointer's qualifier. /// @param TypeAttributeEnum qual - qualifier to add/remove. /// @param bool enabled - true if qualifier should exist false otherwise. /// default is set to false. void setQualifier(TypeAttributeEnum qual, bool enabled); /// @brief Checks if the pointer has a certain qualifier. /// @param TypeAttributeEnum qual - qualifier to check. /// @return true if the qualifier exists and false otherwise. bool hasQualifier(TypeAttributeEnum qual) const; private: /// The type this pointer is pointing at. RefParamType m_pType; /// Array of the pointer's enabled type qualifiers. bool m_qualifiers[ATTR_QUALIFIER_LAST - ATTR_QUALIFIER_FIRST + 1]; /// Pointer's address space. TypeAttributeEnum m_address_space; }; struct VectorType : public ParamType { /// An enumeration to identify the type id of this class. const static TypeEnum enumTy; /// @brief Constructor. /// @param RefParamType the type of each scalar element in the vector. /// @param int the length of the vector. VectorType(const RefParamType type, int len); /// Implementation of Abstract Methods /// /// @brief Visitor service method. (see TypeVisitor for more details). /// When overridden in subclasses, preform a 'double dispatch' to the /// appropriate visit method in the given visitor. /// @param TypeVisitor type visitor. MangleError accept(TypeVisitor*) const; /// @brief Returns a string representation of the underlying type. /// @return type as string. std::string toString() const; /// @brief Returns true if given param type is equal to this type. /// @param ParamType given param type. /// @return true if given param type is equal to this type and false otherwise. bool equals(const ParamType*) const; /// Non-Common Methods /// /// @brief Returns the type the vector is packing. /// @return scalar type. const RefParamType& getScalarType() const { return m_pType; } /// @brief Returns the length of the vector type. /// @return vector type length. int getLength() const { return m_len; } private: /// The scalar type of this vector type. RefParamType m_pType; /// The length of the vector. int m_len; }; struct AtomicType: public ParamType { ///an enumeration to identify the type id of this class const static TypeEnum enumTy; /// @brief Constructor /// @param RefParamType the type refernced as atomic. AtomicType(const RefParamType type); /// Implementation of Abstract Methods /// /// @brief visitor service method. (see TypeVisitor for more details). /// When overridden in subclasses, preform a 'double dispatch' to the /// appropriate visit method in the given visitor. /// @param TypeVisitor type visitor MangleError accept(TypeVisitor*) const; /// @brief returns a string representation of the underlying type. /// @return type as string std::string toString() const; /// @brief returns true if given param type is equal to this type. /// @param ParamType given param type /// @return true if given param type is equal to this type and false otherwise bool equals(const ParamType*) const; /// Non-Common Methods /// /// @brief returns the base type of the atomic parameter. /// @return base type const RefParamType& getBaseType() const { return m_pType; } private: ///the type this pointer is pointing at RefParamType m_pType; }; struct BlockType : public ParamType { ///an enumeration to identify the type id of this class const static TypeEnum enumTy; ///@brief Constructor BlockType(); /// Implementation of Abstract Methods /// /// @brief visitor service method. (see TypeVisitor for more details). /// When overridden in subclasses, preform a 'double dispatch' to the /// appropriate visit method in the given visitor. /// @param TypeVisitor type visitor MangleError accept(TypeVisitor*) const; /// @brief returns a string representation of the underlying type. /// @return type as string std::string toString() const; /// @brief returns true if given param type is equal to this type. /// @param ParamType given param type /// @return true if given param type is equal to this type and false otherwise bool equals(const ParamType*) const; /// Non-Common Methods /// /// @brief returns the number of parameters of the block. /// @return parameters count unsigned int getNumOfParams() const { return (unsigned int)m_params.size(); } ///@brief returns the type of parameter "index" of the block. // @param index the sequential number of the queried parameter ///@return parameter type const RefParamType& getParam(unsigned int index) const { IGC_ASSERT(m_params.size() > index && "index is OOB"); return m_params[index]; } ///@brief set the type of parameter "index" of the block. // @param index the sequential number of the queried parameter // @param type the parameter type void setParam(unsigned int index, RefParamType type) { if(index < getNumOfParams()) { m_params[index] = type; } else if (index == getNumOfParams()) { m_params.push_back(type); } else { IGC_ASSERT(false && "index is OOB"); } } protected: ///an enumeration to identify the primitive type std::vector m_params; }; struct UserDefinedType : public ParamType { /// An enumeration to identify the type id of this class. const static TypeEnum enumTy; /// @brief Constructor. UserDefinedType(const std::string&); /// Implementation of Abstract Methods /// /// @brief Visitor service method. (see TypeVisitor for more details). /// When overridden in subclasses, preform a 'double dispatch' to the /// appropriate visit method in the given visitor. /// @param TypeVisitor type visitor. MangleError accept(TypeVisitor*) const; /// @brief Returns a string representation of the underlying type. /// @return type as string. std::string toString() const; /// @brief Returns true if given param type is equal to this type. /// @param ParamType given param type. /// @return true if given param type is equal to this type and false otherwise. bool equals(const ParamType*) const; protected: /// The name of the user defined type. std::string m_name; }; /// @brief Can be overridden so an object of static type Type* will /// dispatch the correct visit method according to its dynamic type. struct TypeVisitor{ SPIRversion spirVer; TypeVisitor(SPIRversion ver) : spirVer(ver) {}; virtual MangleError visit(const PrimitiveType*) = 0; virtual MangleError visit(const VectorType*) = 0; virtual MangleError visit(const PointerType*) = 0; virtual MangleError visit(const AtomicType*) = 0; virtual MangleError visit(const BlockType*) = 0; virtual MangleError visit(const UserDefinedType*) = 0; }; /// @brief Template dynamic cast function for ParamType derived classes. /// @param ParamType given param type. /// @return required casting type if given param type is an instance if // that type, NULL otherwise. template T* dyn_cast(ParamType* pType) { IGC_ASSERT(pType && "dyn_cast does not support casting of NULL"); return (T::enumTy == pType->getTypeId()) ? (T*)pType : NULL; } /// @brief Template dynamic cast function for ParamType derived classes /// (the constant version). /// @param ParamType given param type. /// @return required casting type if given param type is an instance if // that type, NULL otherwise. template const T* dyn_cast(const ParamType* pType) { IGC_ASSERT(pType && "dyn_cast does not support casting of NULL"); return (T::enumTy == pType->getTypeId()) ? (const T*)pType : NULL; } } // End SPIR namespace #endif //__PARAMETER_TYPE_H__ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/Mangler/Refcount.h000066400000000000000000000040061363533017100260150ustar00rootroot00000000000000//===--------------------------- Refcount.h ------------------------------===// // // SPIR Tools // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// /* * Contributed by: Intel Corporation */ #ifndef __REF_COUNT_H__ #define __REF_COUNT_H__ #include "Probe.h" namespace SPIR { template class RefCount{ public: RefCount(): m_refCount(0), m_ptr(0) { } RefCount(T* ptr): m_ptr(ptr) { m_refCount = new int(1); } RefCount(const RefCount& other) { cpy(other); } ~RefCount() { if (m_refCount) dispose(); } RefCount& operator=(const RefCount& other) { if(this == &other) return *this; if (m_refCount) dispose(); cpy(other); return *this; } void init(T* ptr) { IGC_ASSERT(!m_ptr && "overrunning non NULL pointer"); IGC_ASSERT(!m_refCount && "overrunning non NULL pointer"); m_refCount = new int(1); m_ptr = ptr; } bool isNull() const { return (!m_ptr); } // Pointer access const T& operator*() const{ sanity(); return *m_ptr; } T& operator*() { sanity(); return *m_ptr; } operator T*() { return m_ptr; } operator const T*() const{ return m_ptr; } T* operator->() { return m_ptr; } const T* operator->() const{ return m_ptr; } private: void sanity() const{ IGC_ASSERT(m_ptr && "NULL pointer"); IGC_ASSERT(m_refCount && "NULL ref counter"); IGC_ASSERT(*m_refCount && "zero ref counter"); } void cpy(const RefCount& other) { m_refCount = other.m_refCount; m_ptr = other.m_ptr; if (m_refCount) ++*m_refCount; } void dispose() { sanity(); if (0 == --*m_refCount) { delete m_refCount; delete m_ptr; m_ptr = 0; m_refCount = 0; } } int* m_refCount; T* m_ptr; };// End RefCount } // End SPIR namespace #endif//__REF_COUNT_H__ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/SPIRVInternal.h000066400000000000000000001060021363533017100252420ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVInternal.h - SPIR-V internal header file --------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file declares classes and functions shared by SPIR-V reader/writer. /// //===----------------------------------------------------------------------===// #ifndef SPIRVINTERNAL_HPP_ #define SPIRVINTERNAL_HPP_ #define DEBUG_TYPE "spirv" #include "libSPIRV/SPIRVUtil.h" #include "libSPIRV/SPIRVEnum.h" #include "libSPIRV/SPIRVError.h" #include "libSPIRV/SPIRVType.h" #include "common/LLVMWarningsPush.hpp" #include "llvmWrapper/IR/Attributes.h" #include "llvm/ADT/StringSwitch.h" #include #include #include "llvm/IR/Attributes.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ToolOutputFile.h" #include "common/LLVMWarningsPop.hpp" #include "../../inc/common/UFO/portable_compiler.h" #include #include namespace spv { using namespace llvm; namespace kOCLTypeQualifierName { __attr_unused const static char *Const = "const"; __attr_unused const static char *Volatile = "volatile"; __attr_unused const static char *Restrict = "restrict"; __attr_unused const static char *Pipe = "pipe"; } template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,y) add(Instruction::x, Op##y); /* Casts */ _SPIRV_OP(ZExt, UConvert) _SPIRV_OP(SExt, SConvert) _SPIRV_OP(Trunc, UConvert) _SPIRV_OP(FPToUI, ConvertFToU) _SPIRV_OP(FPToSI, ConvertFToS) _SPIRV_OP(UIToFP, ConvertUToF) _SPIRV_OP(SIToFP, ConvertSToF) _SPIRV_OP(FPTrunc, FConvert) _SPIRV_OP(FPExt, FConvert) _SPIRV_OP(PtrToInt, ConvertPtrToU) _SPIRV_OP(IntToPtr, ConvertUToPtr) _SPIRV_OP(BitCast, Bitcast) _SPIRV_OP(GetElementPtr, AccessChain) /*Binary*/ _SPIRV_OP(And, BitwiseAnd) _SPIRV_OP(Or, BitwiseOr) _SPIRV_OP(Xor, BitwiseXor) _SPIRV_OP(Add, IAdd) _SPIRV_OP(FAdd, FAdd) _SPIRV_OP(Sub, ISub) _SPIRV_OP(FSub, FSub) _SPIRV_OP(Mul, IMul) _SPIRV_OP(FMul, FMul) _SPIRV_OP(UDiv, UDiv) _SPIRV_OP(SDiv, SDiv) _SPIRV_OP(FDiv, FDiv) _SPIRV_OP(SRem, SRem) _SPIRV_OP(URem, UMod) _SPIRV_OP(Shl, ShiftLeftLogical) _SPIRV_OP(LShr, ShiftRightLogical) _SPIRV_OP(AShr, ShiftRightArithmetic) #undef _SPIRV_OP } typedef SPIRVMap OpCodeMap; template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,y) add(CmpInst::x, Op##y); _SPIRV_OP(FCMP_OEQ, FOrdEqual) _SPIRV_OP(FCMP_OGT, FOrdGreaterThan) _SPIRV_OP(FCMP_OGE, FOrdGreaterThanEqual) _SPIRV_OP(FCMP_OLT, FOrdLessThan) _SPIRV_OP(FCMP_OLE, FOrdLessThanEqual) _SPIRV_OP(FCMP_ONE, FOrdNotEqual) _SPIRV_OP(FCMP_ORD, Ordered) _SPIRV_OP(FCMP_UNO, Unordered) _SPIRV_OP(FCMP_UEQ, FUnordEqual) _SPIRV_OP(FCMP_UGT, FUnordGreaterThan) _SPIRV_OP(FCMP_UGE, FUnordGreaterThanEqual) _SPIRV_OP(FCMP_ULT, FUnordLessThan) _SPIRV_OP(FCMP_ULE, FUnordLessThanEqual) _SPIRV_OP(FCMP_UNE, FUnordNotEqual) _SPIRV_OP(ICMP_EQ, IEqual) _SPIRV_OP(ICMP_NE, INotEqual) _SPIRV_OP(ICMP_EQ, LogicalEqual) _SPIRV_OP(ICMP_NE, LogicalNotEqual) _SPIRV_OP(ICMP_UGT, UGreaterThan) _SPIRV_OP(ICMP_UGE, UGreaterThanEqual) _SPIRV_OP(ICMP_ULT, ULessThan) _SPIRV_OP(ICMP_ULE, ULessThanEqual) _SPIRV_OP(ICMP_SGT, SGreaterThan) _SPIRV_OP(ICMP_SGE, SGreaterThanEqual) _SPIRV_OP(ICMP_SLT, SLessThan) _SPIRV_OP(ICMP_SLE, SLessThanEqual) #undef _SPIRV_OP } typedef SPIRVMap CmpMap; class IntBoolOpMapId; template<> inline void SPIRVMap::init() { add(OpIEqual, OpLogicalEqual); add(OpINotEqual, OpLogicalNotEqual); add(OpNot, OpLogicalNot); add(OpBitwiseAnd, OpLogicalAnd); add(OpBitwiseOr, OpLogicalOr); add(OpBitwiseXor, OpLogicalNotEqual); } typedef SPIRVMap IntBoolOpMap; #define SPIR_TARGETTRIPLE32 "spir-unknown-unknown" #define SPIR_TARGETTRIPLE64 "spir64-unknown-unknown" #define SPIR_DATALAYOUT32 "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32"\ "-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32"\ "-v32:32:32-v48:64:64-v64:64:64-v96:128:128"\ "-v128:128:128-v192:256:256-v256:256:256"\ "-v512:512:512-v1024:1024:1024" #define SPIR_DATALAYOUT64 "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32"\ "-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32"\ "-v32:32:32-v48:64:64-v64:64:64-v96:128:128"\ "-v128:128:128-v192:256:256-v256:256:256"\ "-v512:512:512-v1024:1024:1024" enum SPIRAddressSpace { SPIRAS_Private, SPIRAS_Global, SPIRAS_Constant, SPIRAS_Local, SPIRAS_Generic, SPIRAS_Count, SPIRAS_Input, }; enum OCLMemFenceKind { OCLMF_Local = 1, OCLMF_Global = 2, OCLMF_Image = 4, }; enum OCLMemScopeKind { OCLMS_work_item, OCLMS_work_group, OCLMS_device, OCLMS_all_svm_devices, OCLMS_sub_group, }; enum OCLMemOrderKind { OCLMO_relaxed, OCLMO_acquire, OCLMO_release, OCLMO_acq_rel, OCLMO_seq_cst }; template<> inline void SPIRVMap::init() { add(SPIRAS_Private, StorageClassFunction); add(SPIRAS_Global, StorageClassWorkgroupGlobal); add(SPIRAS_Constant, StorageClassUniformConstant); add(SPIRAS_Local, StorageClassWorkgroupLocal); add(SPIRAS_Generic, StorageClassGeneric); add(SPIRAS_Input, StorageClassInput); } typedef SPIRVMap SPIRSPIRVAddrSpaceMap; // Maps OCL builtin function to SPIRV builtin variable. template<> inline void SPIRVMap::init() { add("read_only", AccessQualifierReadOnly); add("write_only", AccessQualifierWriteOnly); add("read_write", AccessQualifierReadWrite); } typedef SPIRVMap SPIRSPIRVAccessQualifierMap; template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,y) add(#x, OpType##y); _SPIRV_OP(opencl.event_t, Event) _SPIRV_OP(opencl.pipe_t, Pipe) _SPIRV_OP(opencl.clk_event_t, DeviceEvent) _SPIRV_OP(opencl.reserve_id_t, ReserveId) _SPIRV_OP(opencl.queue_t, Queue) #undef _SPIRV_OP } typedef SPIRVMap BuiltinOpaqueGenericTypeOpCodeMap; class mapSPIRVBuiltinVariableKind; template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x, ...) add(spv::BuiltIn::x, #x); #include "libSPIRV/SPIRVBuiltinEnum.h" #undef _SPIRV_OP } typedef SPIRVMap SPIRSPIRVBuiltinVariableMap; // Maps uniqued builtin function name to SPIRV instruction. template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x) add(x, #x); // Memory _SPIRV_OP(OpGenericPtrMemSemantics) // Atomics _SPIRV_OP(OpAtomicAnd) _SPIRV_OP(OpAtomicCompareExchange) _SPIRV_OP(OpAtomicCompareExchangeWeak) _SPIRV_OP(OpAtomicExchange) _SPIRV_OP(OpAtomicFlagClear) _SPIRV_OP(OpAtomicFlagTestAndSet) _SPIRV_OP(OpAtomicIAdd) _SPIRV_OP(OpAtomicIDecrement) _SPIRV_OP(OpAtomicIIncrement) _SPIRV_OP(OpAtomicISub) _SPIRV_OP(OpAtomicLoad) _SPIRV_OP(OpAtomicOr) _SPIRV_OP(OpAtomicSMax) _SPIRV_OP(OpAtomicSMin) _SPIRV_OP(OpAtomicStore) _SPIRV_OP(OpAtomicUMax) _SPIRV_OP(OpAtomicUMin) _SPIRV_OP(OpAtomicXor) _SPIRV_OP(OpDot) _SPIRV_OP(OpGroupAsyncCopy) _SPIRV_OP(OpGroupWaitEvents) _SPIRV_OP(OpFOrdEqual) _SPIRV_OP(OpFUnordNotEqual) _SPIRV_OP(OpFOrdGreaterThan) _SPIRV_OP(OpFOrdGreaterThanEqual) _SPIRV_OP(OpFOrdLessThan) _SPIRV_OP(OpFOrdLessThanEqual) _SPIRV_OP(OpLessOrGreater) _SPIRV_OP(OpOrdered) _SPIRV_OP(OpUnordered) _SPIRV_OP(OpIsFinite) _SPIRV_OP(OpIsInf) _SPIRV_OP(OpIsNan) _SPIRV_OP(OpIsNormal) _SPIRV_OP(OpSignBitSet) _SPIRV_OP(OpAny) _SPIRV_OP(OpAll) // CL 2.0 kernel enqueue builtins _SPIRV_OP(OpEnqueueMarker) _SPIRV_OP(OpEnqueueKernel) _SPIRV_OP(OpGetKernelNDrangeSubGroupCount) _SPIRV_OP(OpGetKernelNDrangeMaxSubGroupSize) _SPIRV_OP(OpGetKernelWorkGroupSize) _SPIRV_OP(OpGetKernelPreferredWorkGroupSizeMultiple) _SPIRV_OP(OpRetainEvent) _SPIRV_OP(OpReleaseEvent) _SPIRV_OP(OpCreateUserEvent) _SPIRV_OP(OpIsValidEvent) _SPIRV_OP(OpSetUserEventStatus) _SPIRV_OP(OpCaptureEventProfilingInfo) _SPIRV_OP(OpGetDefaultQueue) _SPIRV_OP(OpBuildNDRange) _SPIRV_OP(OpGetKernelLocalSizeForSubgroupCount) _SPIRV_OP(OpGetKernelMaxNumSubgroups) // Barriers _SPIRV_OP(OpMemoryBarrier) _SPIRV_OP(OpControlBarrier) _SPIRV_OP(OpNamedBarrierInitialize) _SPIRV_OP(OpMemoryNamedBarrier) // CL 2.0 pipe builtins _SPIRV_OP(OpReadPipe) _SPIRV_OP(OpWritePipe) _SPIRV_OP(OpReservedReadPipe) _SPIRV_OP(OpReservedWritePipe) _SPIRV_OP(OpReserveReadPipePackets) _SPIRV_OP(OpReserveWritePipePackets) _SPIRV_OP(OpCommitReadPipe) _SPIRV_OP(OpCommitWritePipe) _SPIRV_OP(OpIsValidReserveId) _SPIRV_OP(OpGroupReserveReadPipePackets) _SPIRV_OP(OpGroupReserveWritePipePackets) _SPIRV_OP(OpGroupCommitReadPipe) _SPIRV_OP(OpGroupCommitWritePipe) _SPIRV_OP(OpGetNumPipePackets) _SPIRV_OP(OpGetMaxPipePackets) // Arithmetic Instructions _SPIRV_OP(OpUMulExtended) _SPIRV_OP(OpSMulExtended) // Bit Instructions _SPIRV_OP(OpBitFieldInsert) _SPIRV_OP(OpBitFieldSExtract) _SPIRV_OP(OpBitFieldUExtract) _SPIRV_OP(OpBitReverse) _SPIRV_OP(OpBitCount) // CL 2.0 workgroup/subgroup builtins _SPIRV_OP(OpGroupAll) _SPIRV_OP(OpGroupAny) _SPIRV_OP(OpGroupBroadcast) _SPIRV_OP(OpGroupFAdd) _SPIRV_OP(OpGroupFMax) _SPIRV_OP(OpGroupFMin) _SPIRV_OP(OpGroupIAdd) _SPIRV_OP(OpGroupSMax) _SPIRV_OP(OpGroupSMin) _SPIRV_OP(OpGroupUMax) _SPIRV_OP(OpGroupUMin) // SPIR-V 1.3 non uniform subgroup builtins _SPIRV_OP(OpGroupNonUniformElect) _SPIRV_OP(OpGroupNonUniformAll) _SPIRV_OP(OpGroupNonUniformAny) _SPIRV_OP(OpGroupNonUniformAllEqual) _SPIRV_OP(OpGroupNonUniformBroadcast) _SPIRV_OP(OpGroupNonUniformBroadcastFirst) _SPIRV_OP(OpGroupNonUniformBallot) _SPIRV_OP(OpGroupNonUniformInverseBallot) _SPIRV_OP(OpGroupNonUniformBallotBitExtract) _SPIRV_OP(OpGroupNonUniformBallotBitCount) _SPIRV_OP(OpGroupNonUniformBallotFindLSB) _SPIRV_OP(OpGroupNonUniformBallotFindMSB) _SPIRV_OP(OpGroupNonUniformShuffle) _SPIRV_OP(OpGroupNonUniformShuffleXor) _SPIRV_OP(OpGroupNonUniformShuffleUp) _SPIRV_OP(OpGroupNonUniformShuffleDown) _SPIRV_OP(OpGroupNonUniformIAdd) _SPIRV_OP(OpGroupNonUniformFAdd) _SPIRV_OP(OpGroupNonUniformIMul) _SPIRV_OP(OpGroupNonUniformFMul) _SPIRV_OP(OpGroupNonUniformSMin) _SPIRV_OP(OpGroupNonUniformUMin) _SPIRV_OP(OpGroupNonUniformFMin) _SPIRV_OP(OpGroupNonUniformSMax) _SPIRV_OP(OpGroupNonUniformUMax) _SPIRV_OP(OpGroupNonUniformFMax) _SPIRV_OP(OpGroupNonUniformBitwiseAnd) _SPIRV_OP(OpGroupNonUniformBitwiseOr) _SPIRV_OP(OpGroupNonUniformBitwiseXor) _SPIRV_OP(OpGroupNonUniformLogicalAnd) _SPIRV_OP(OpGroupNonUniformLogicalOr) _SPIRV_OP(OpGroupNonUniformLogicalXor) // CL image builtins _SPIRV_OP(OpSampledImage) _SPIRV_OP(OpImageSampleImplicitLod) _SPIRV_OP(OpImageSampleExplicitLod) _SPIRV_OP(OpImageRead) _SPIRV_OP(OpImageWrite) _SPIRV_OP(OpImageQuerySize) _SPIRV_OP(OpImageQuerySizeLod) _SPIRV_OP(OpImageQueryFormat) _SPIRV_OP(OpImageQueryOrder) _SPIRV_OP(OpImageQueryLevels) _SPIRV_OP(OpImageQuerySamples) // Conversion builtins _SPIRV_OP(OpUConvert) _SPIRV_OP(OpSConvert) _SPIRV_OP(OpConvertFToU) _SPIRV_OP(OpConvertFToS) _SPIRV_OP(OpConvertUToF) _SPIRV_OP(OpConvertSToF) _SPIRV_OP(OpFConvert) _SPIRV_OP(OpSatConvertUToS) _SPIRV_OP(OpSatConvertSToU) // Arithmetic Instructions _SPIRV_OP(OpFRem) _SPIRV_OP(OpFMod) // Cast _SPIRV_OP(OpGenericCastToPtrExplicit) // Ballot extension _SPIRV_OP(OpSubgroupBallotKHR) _SPIRV_OP(OpSubgroupFirstInvocationKHR) // Shader clock extension _SPIRV_OP(OpReadClockKHR) #undef _SPIRV_OP #define _SPIRV_OP(x, y) add(Op##y, #x); // Intel Subgroups builtins _SPIRV_OP(intel_sub_group_shuffle, SubgroupShuffleINTEL) _SPIRV_OP(intel_sub_group_shuffle_down, SubgroupShuffleDownINTEL) _SPIRV_OP(intel_sub_group_shuffle_up, SubgroupShuffleUpINTEL) _SPIRV_OP(intel_sub_group_shuffle_xor, SubgroupShuffleXorINTEL) // Intel media_block_io builtins _SPIRV_OP(intel_sub_group_media_block_read, SubgroupImageMediaBlockReadINTEL) _SPIRV_OP(intel_sub_group_media_block_write, SubgroupImageMediaBlockWriteINTEL) #undef _SPIRV_OP // VME #define _SPIRV_OP(x) add(x, #x); _SPIRV_OP(OpVmeImageINTEL) #undef _SPIRV_OP #define _SPIRV_OP(x,y) \ add(OpSubgroupAvc##y##INTEL, "intel_sub_group_avc_"#x); // Initialization phase functions _SPIRV_OP(ime_initialize, ImeInitialize) _SPIRV_OP(fme_initialize, FmeInitialize) _SPIRV_OP(bme_initialize, BmeInitialize) _SPIRV_OP(sic_initialize, SicInitialize) // Result and payload types conversion functions _SPIRV_OP(mce_convert_to_ime_payload, MceConvertToImePayload) _SPIRV_OP(mce_convert_to_ime_result, MceConvertToImeResult) _SPIRV_OP(mce_convert_to_ref_payload, MceConvertToRefPayload) _SPIRV_OP(mce_convert_to_ref_result, MceConvertToRefResult) _SPIRV_OP(mce_convert_to_sic_payload, MceConvertToSicPayload) _SPIRV_OP(mce_convert_to_sic_result, MceConvertToSicResult) _SPIRV_OP(ime_convert_to_mce_payload, ImeConvertToMcePayload) _SPIRV_OP(ime_convert_to_mce_result, ImeConvertToMceResult) _SPIRV_OP(ref_convert_to_mce_payload, RefConvertToMcePayload) _SPIRV_OP(ref_convert_to_mce_result, RefConvertToMceResult) _SPIRV_OP(sic_convert_to_mce_payload, SicConvertToMcePayload) _SPIRV_OP(sic_convert_to_mce_result, SicConvertToMceResult) #undef _SPIRV_OP // MCE instructions #define _SPIRV_OP(x,y) \ add(OpSubgroupAvcMce##y##INTEL, "intel_sub_group_avc_mce_"#x); _SPIRV_OP(get_default_inter_base_multi_reference_penalty, GetDefaultInterBaseMultiReferencePenalty) _SPIRV_OP(set_inter_base_multi_reference_penalty, SetInterBaseMultiReferencePenalty) _SPIRV_OP(get_default_inter_shape_penalty, GetDefaultInterShapePenalty) _SPIRV_OP(set_inter_shape_penalty, SetInterShapePenalty) _SPIRV_OP(get_default_inter_direction_penalty, GetDefaultInterDirectionPenalty) _SPIRV_OP(set_inter_direction_penalty, SetInterDirectionPenalty) _SPIRV_OP(get_default_intra_luma_shape_penalty, GetDefaultIntraLumaShapePenalty) _SPIRV_OP(get_default_inter_motion_vector_cost_table, GetDefaultInterMotionVectorCostTable) _SPIRV_OP(get_default_high_penalty_cost_table, GetDefaultHighPenaltyCostTable) _SPIRV_OP(get_default_medium_penalty_cost_table, GetDefaultMediumPenaltyCostTable) _SPIRV_OP(get_default_low_penalty_cost_table, GetDefaultLowPenaltyCostTable) _SPIRV_OP(set_motion_vector_cost_function, SetMotionVectorCostFunction) _SPIRV_OP(get_default_intra_luma_mode_penalty, GetDefaultIntraLumaModePenalty) _SPIRV_OP(get_default_non_dc_luma_intra_penalty, GetDefaultNonDcLumaIntraPenalty) _SPIRV_OP(get_default_intra_chroma_mode_base_penalty, GetDefaultIntraChromaModeBasePenalty) _SPIRV_OP(set_ac_only_haar, SetAcOnlyHaar) _SPIRV_OP(set_source_interlaced_field_polarity, SetSourceInterlacedFieldPolarity) _SPIRV_OP(set_single_reference_interlaced_field_polarity, SetSingleReferenceInterlacedFieldPolarity) _SPIRV_OP(set_dual_reference_interlaced_field_polarities, SetDualReferenceInterlacedFieldPolarities) _SPIRV_OP(get_motion_vectors, GetMotionVectors) _SPIRV_OP(get_inter_distortions, GetInterDistortions) _SPIRV_OP(get_best_inter_distortion, GetBestInterDistortions) _SPIRV_OP(get_inter_major_shape, GetInterMajorShape) _SPIRV_OP(get_inter_minor_shapes, GetInterMinorShape) _SPIRV_OP(get_inter_directions, GetInterDirections) _SPIRV_OP(get_inter_motion_vector_count, GetInterMotionVectorCount) _SPIRV_OP(get_inter_reference_ids, GetInterReferenceIds) _SPIRV_OP(get_inter_reference_interlaced_field_polarities, GetInterReferenceInterlacedFieldPolarities) #undef _SPIRV_OP // IME instructions #define _SPIRV_OP(x,y) \ add(OpSubgroupAvcIme##y##INTEL, "intel_sub_group_avc_ime_"#x); _SPIRV_OP(set_single_reference, SetSingleReference) _SPIRV_OP(set_dual_reference, SetDualReference) _SPIRV_OP(ref_window_size, RefWindowSize) _SPIRV_OP(adjust_ref_offset, AdjustRefOffset) _SPIRV_OP(set_max_motion_vector_count, SetMaxMotionVectorCount) _SPIRV_OP(set_unidirectional_mix_disable, SetUnidirectionalMixDisable) _SPIRV_OP(set_early_search_termination_threshold, SetEarlySearchTerminationThreshold) _SPIRV_OP(set_weighted_sad, SetWeightedSad) _SPIRV_OP(evaluate_with_single_reference, EvaluateWithSingleReference) _SPIRV_OP(evaluate_with_dual_reference, EvaluateWithDualReference) _SPIRV_OP(evaluate_with_single_reference_streamin, EvaluateWithSingleReferenceStreamin) _SPIRV_OP(evaluate_with_dual_reference_streamin, EvaluateWithDualReferenceStreamin) _SPIRV_OP(evaluate_with_single_reference_streamout, EvaluateWithSingleReferenceStreamout) _SPIRV_OP(evaluate_with_dual_reference_streamout, EvaluateWithDualReferenceStreamout) _SPIRV_OP(evaluate_with_single_reference_streaminout, EvaluateWithSingleReferenceStreaminout) _SPIRV_OP(evaluate_with_dual_reference_streaminout, EvaluateWithDualReferenceStreaminout) _SPIRV_OP(get_single_reference_streamin, GetSingleReferenceStreamin) _SPIRV_OP(get_dual_reference_streamin, GetDualReferenceStreamin) _SPIRV_OP(strip_single_reference_streamout, StripSingleReferenceStreamout) _SPIRV_OP(strip_dual_reference_streamout, StripDualReferenceStreamout) _SPIRV_OP(get_border_reached, GetBorderReached) _SPIRV_OP(get_truncated_search_indication, GetTruncatedSearchIndication) _SPIRV_OP(get_unidirectional_early_search_termination, GetUnidirectionalEarlySearchTermination) _SPIRV_OP(get_weighting_pattern_minimum_motion_vector, GetWeightingPatternMinimumMotionVector) _SPIRV_OP(get_weighting_pattern_minimum_distortion, GetWeightingPatternMinimumDistortion) #undef _SPIRV_OP #define _SPIRV_OP(x,y) \ add(OpSubgroupAvcImeGetStreamout##y##INTEL, \ "intel_sub_group_avc_ime_get_streamout_major_shape_"#x); _SPIRV_OP(motion_vectors, SingleReferenceMajorShapeMotionVectors) _SPIRV_OP(distortions, SingleReferenceMajorShapeDistortions) _SPIRV_OP(reference_ids, SingleReferenceMajorShapeReferenceIds) _SPIRV_OP(motion_vectors, DualReferenceMajorShapeMotionVectors) _SPIRV_OP(distortions, DualReferenceMajorShapeDistortions) _SPIRV_OP(reference_ids, DualReferenceMajorShapeReferenceIds) #undef _SPIRV_OP // REF instructions #define _SPIRV_OP(x,y) \ add(OpSubgroupAvcRef##y##INTEL, "intel_sub_group_avc_ref_"#x); _SPIRV_OP(set_bidirectional_mix_disable, SetBidirectionalMixDisable) _SPIRV_OP(set_bilinear_filter_enable, SetBilinearFilterEnable) _SPIRV_OP(evaluate_with_single_reference, EvaluateWithSingleReference) _SPIRV_OP(evaluate_with_dual_reference, EvaluateWithDualReference) _SPIRV_OP(evaluate_with_multi_reference, EvaluateWithMultiReference) _SPIRV_OP(evaluate_with_multi_reference, EvaluateWithMultiReferenceInterlaced) #undef _SPIRV_OP // SIC instructions #define _SPIRV_OP(x,y) \ add(OpSubgroupAvcSic##y##INTEL, "intel_sub_group_avc_sic_"#x); _SPIRV_OP(configure_skc, ConfigureSkc) _SPIRV_OP(configure_ipe, ConfigureIpeLuma) _SPIRV_OP(configure_ipe, ConfigureIpeLumaChroma) _SPIRV_OP(get_motion_vector_mask, GetMotionVectorMask) _SPIRV_OP(set_intra_luma_shape_penalty, SetIntraLumaShapePenalty) _SPIRV_OP(set_intra_luma_mode_cost_function, SetIntraLumaModeCostFunction) _SPIRV_OP(set_intra_chroma_mode_cost_function, SetIntraChromaModeCostFunction) _SPIRV_OP(set_skc_bilinear_filter_enable, SetBilinearFilterEnable) _SPIRV_OP(set_skc_forward_transform_enable, SetSkcForwardTransformEnable) _SPIRV_OP(set_block_based_raw_skip_sad, SetBlockBasedRawSkipSad) _SPIRV_OP(evaluate_ipe, EvaluateIpe) _SPIRV_OP(evaluate_with_single_reference, EvaluateWithSingleReference) _SPIRV_OP(evaluate_with_dual_reference, EvaluateWithDualReference) _SPIRV_OP(evaluate_with_multi_reference, EvaluateWithMultiReference) _SPIRV_OP(evaluate_with_multi_reference, EvaluateWithMultiReferenceInterlaced) _SPIRV_OP(get_ipe_luma_shape, GetIpeLumaShape) _SPIRV_OP(get_best_ipe_luma_distortion, GetBestIpeLumaDistortion) _SPIRV_OP(get_best_ipe_chroma_distortion, GetBestIpeChromaDistortion) _SPIRV_OP(get_packed_ipe_luma_modes, GetPackedIpeLumaModes) _SPIRV_OP(get_ipe_chroma_mode, GetIpeChromaMode) _SPIRV_OP(get_packed_skc_luma_count_threshold, GetPackedSkcLumaCountThreshold) _SPIRV_OP(get_packed_skc_luma_sum_threshold, GetPackedSkcLumaSumThreshold) _SPIRV_OP(get_inter_raw_sads, GetInterRawSads) #undef _SPIRV_OP } typedef SPIRVMap OCLSPIRVBuiltinMap; template<> inline void SPIRVMap::init() { add(Attribute::ZExt, FunctionParameterAttributeZext); add(Attribute::SExt, FunctionParameterAttributeSext); add(Attribute::ByVal, FunctionParameterAttributeByVal); add(Attribute::StructRet, FunctionParameterAttributeSret); add(Attribute::NoAlias, FunctionParameterAttributeNoAlias); add(Attribute::NoCapture, FunctionParameterAttributeNoCapture); add(Attribute::ReadOnly, FunctionParameterAttributeNoWrite); add(Attribute::ReadNone, FunctionParameterAttributeNoReadWrite); } typedef SPIRVMap SPIRSPIRVFuncParamAttrMap; template<> inline void SPIRVMap::init() { add(Attribute::ReadOnly, FunctionControlPureMask); add(Attribute::ReadNone, FunctionControlConstMask); add(Attribute::AlwaysInline, FunctionControlInlineMask); add(Attribute::NoInline, FunctionControlDontInlineMask); } typedef SPIRVMap SPIRSPIRVFuncCtlMaskMap; template<> inline void SPIRVMap::init() { add(OCLMF_Local, MemorySemanticsWorkgroupLocalMemoryMask); add(OCLMF_Global, MemorySemanticsWorkgroupGlobalMemoryMask); add(OCLMF_Image, MemorySemanticsImageMemoryMask); } typedef SPIRVMap OCLMemFenceMap; template<> inline void SPIRVMap::init() { add(OCLMO_relaxed, MemorySemanticsMaskNone); //old MemorySemanticsRelaxedMask add(OCLMO_acquire, MemorySemanticsAcquireMask); add(OCLMO_release, MemorySemanticsReleaseMask); add(OCLMO_acq_rel, MemorySemanticsAcquireMask|MemorySemanticsReleaseMask); add(OCLMO_seq_cst, MemorySemanticsSequentiallyConsistentMask); } typedef SPIRVMap OCLMemOrderMap; inline unsigned mapOCLMemSemanticToSPIRV(unsigned MemFenceFlag, OCLMemOrderKind Order) { return OCLMemOrderMap::map(Order) | mapBitMask(MemFenceFlag); } inline std::pair mapSPIRVMemSemanticToOCL(unsigned Sema) { return std::make_pair(rmapBitMask(Sema), OCLMemOrderMap::rmap(Sema & 0xF)); } inline OCLMemOrderKind mapSPIRVMemOrderToOCL(unsigned Sema) { return OCLMemOrderMap::rmap(Sema & 0xF); } template<> inline void SPIRVMap::init() { add(OCLMS_work_item, ScopeInvocation); add(OCLMS_work_group, ScopeWorkgroup); add(OCLMS_device, ScopeDevice); add(OCLMS_all_svm_devices, ScopeCrossDevice); add(OCLMS_sub_group, ScopeSubgroup); } typedef SPIRVMap OCLMemScopeMap; template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,y) add(#x, spv::GroupOperation::y); _SPIRV_OP(reduce, GroupOperationReduce) _SPIRV_OP(scan_inclusive, GroupOperationInclusiveScan) _SPIRV_OP(scan_exclusive, GroupOperationExclusiveScan) _SPIRV_OP(clustered_reduce, GroupOperationClusteredReduce) #undef _SPIRV_OP } typedef SPIRVMap SPIRSPIRVGroupOperationMap; template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,y) add("rt"#x, SPIRVFPRoundingModeKind::y); _SPIRV_OP(e, FPRoundingModeRTE) _SPIRV_OP(z, FPRoundingModeRTZ) _SPIRV_OP(p, FPRoundingModeRTP) _SPIRV_OP(n, FPRoundingModeRTN) #undef _SPIRV_OP } typedef SPIRVMap SPIRSPIRVFPRoundingModeMap; #define SPIR_MD_KERNELS "opencl.kernels" #define SPIR_MD_KERNEL_ARG_ADDR_SPACE "kernel_arg_addr_space" #define SPIR_MD_KERNEL_ARG_ACCESS_QUAL "kernel_arg_access_qual" #define SPIR_MD_KERNEL_ARG_TYPE "kernel_arg_type" #define SPIR_MD_KERNEL_ARG_BASE_TYPE "kernel_arg_base_type" #define SPIR_MD_KERNEL_ARG_TYPE_QUAL "kernel_arg_type_qual" #define SPIR_MD_KERNEL_ARG_NAME "kernel_arg_name" namespace kLLVMName { const static char builtinPrefix[] = "__builtin_spirv_"; const static char builtinExtInstPrefixOpenCL[] = "__builtin_spirv_OpenCL_"; } namespace kSPIRVTypeName { const static char Delimiter = '.'; const static char SampledImage[] = "OpTypeSampledImage"; const static char Sampler[] = "OpTypeSampler"; const static char Image[] = "OpTypeImage"; const static char Pipe[] = "OpTypePipe"; } namespace kSPR2TypeName { const static char Delimiter = '.'; const static char OCLPrefix[] = "opencl."; const static char ImagePrefix[] = "opencl.image"; const static char Sampler[] = "opencl.sampler_t"; const static char Event[] = "opencl.event_t"; } namespace kAccessQualName { const static char ReadOnly[] = "read_only"; const static char WriteOnly[] = "write_only"; const static char ReadWrite[] = "read_write"; } namespace kSPIRVMD { const static char Capability[] = "spirv.Capability"; const static char Extension[] = "spirv.Extension"; const static char Source[] = "spirv.Source"; const static char SourceExtension[] = "spirv.SourceExtension"; const static char MemoryModel[] = "spirv.MemoryModel"; const static char EntryPoint[] = "spirv.EntryPoint"; const static char ExecutionMode[] = "spirv.ExecutionMode"; } namespace kSPIR2MD { const static char Extensions[] = "opencl.used.extensions"; const static char FPContract[] = "opencl.enable.FP_CONTRACT"; const static char OCLVer[] = "opencl.ocl.version"; const static char OptFeatures[] = "opencl.used.optional.core.features"; const static char SPIRVer[] = "opencl.spir.version"; const static char VecTyHint[] = "vec_type_hint"; const static char WGSize[] = "reqd_work_group_size"; const static char ReqdSubgroupSize[] = "intel_reqd_sub_group_size"; const static char WGSizeHint[] = "work_group_size_hint"; } enum Spir2SamplerKind { CLK_ADDRESS_NONE = 0x0000, CLK_ADDRESS_CLAMP = 0x0004, CLK_ADDRESS_CLAMP_TO_EDGE = 0x0002, CLK_ADDRESS_REPEAT = 0x0006, CLK_ADDRESS_MIRRORED_REPEAT = 0x0008, CLK_NORMALIZED_COORDS_FALSE = 0x0000, CLK_NORMALIZED_COORDS_TRUE = 0x0001, CLK_FILTER_NEAREST = 0x0010, CLK_FILTER_LINEAR = 0x0020, }; namespace OclExt { enum Kind { #define _SPIRV_OP(x) x, _SPIRV_OP(cl_images) _SPIRV_OP(cl_doubles) _SPIRV_OP(cl_khr_int64_base_atomics) _SPIRV_OP(cl_khr_int64_extended_atomics) _SPIRV_OP(cl_khr_fp16) _SPIRV_OP(cl_khr_gl_sharing) _SPIRV_OP(cl_khr_gl_event) _SPIRV_OP(cl_khr_d3d10_sharing) _SPIRV_OP(cl_khr_media_sharing) _SPIRV_OP(cl_khr_d3d11_sharing) _SPIRV_OP(cl_khr_global_int32_base_atomics) _SPIRV_OP(cl_khr_global_int32_extended_atomics) _SPIRV_OP(cl_khr_local_int32_base_atomics) _SPIRV_OP(cl_khr_local_int32_extended_atomics) _SPIRV_OP(cl_khr_byte_addressable_store) _SPIRV_OP(cl_khr_3d_image_writes) _SPIRV_OP(cl_khr_gl_msaa_sharing) _SPIRV_OP(cl_khr_depth_images) _SPIRV_OP(cl_khr_gl_depth_images) _SPIRV_OP(cl_khr_subgroups) _SPIRV_OP(cl_khr_mipmap_image) _SPIRV_OP(cl_khr_mipmap_image_writes) _SPIRV_OP(cl_khr_egl_event) _SPIRV_OP(cl_khr_srgb_image_writes) #undef _SPIRV_OP }; } template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x) add(OclExt::x, #x); _SPIRV_OP(cl_images) _SPIRV_OP(cl_doubles) _SPIRV_OP(cl_khr_int64_base_atomics) _SPIRV_OP(cl_khr_int64_extended_atomics) _SPIRV_OP(cl_khr_fp16) _SPIRV_OP(cl_khr_gl_sharing) _SPIRV_OP(cl_khr_gl_event) _SPIRV_OP(cl_khr_d3d10_sharing) _SPIRV_OP(cl_khr_media_sharing) _SPIRV_OP(cl_khr_d3d11_sharing) _SPIRV_OP(cl_khr_global_int32_base_atomics) _SPIRV_OP(cl_khr_global_int32_extended_atomics) _SPIRV_OP(cl_khr_local_int32_base_atomics) _SPIRV_OP(cl_khr_local_int32_extended_atomics) _SPIRV_OP(cl_khr_byte_addressable_store) _SPIRV_OP(cl_khr_3d_image_writes) _SPIRV_OP(cl_khr_gl_msaa_sharing) _SPIRV_OP(cl_khr_depth_images) _SPIRV_OP(cl_khr_gl_depth_images) _SPIRV_OP(cl_khr_subgroups) _SPIRV_OP(cl_khr_mipmap_image) _SPIRV_OP(cl_khr_mipmap_image_writes) _SPIRV_OP(cl_khr_egl_event) _SPIRV_OP(cl_khr_srgb_image_writes) #undef _SPIRV_OP }; template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,y) add(OclExt::x, SPIRVCapabilityKind::y); _SPIRV_OP(cl_images, CapabilityImageBasic) _SPIRV_OP(cl_doubles, CapabilityFloat64) _SPIRV_OP(cl_khr_int64_base_atomics, CapabilityInt64Atomics) _SPIRV_OP(cl_khr_int64_extended_atomics, CapabilityInt64Atomics) _SPIRV_OP(cl_khr_fp16, CapabilityFloat16) _SPIRV_OP(cl_khr_gl_sharing, CapabilityNone) _SPIRV_OP(cl_khr_gl_event, CapabilityNone) _SPIRV_OP(cl_khr_d3d10_sharing, CapabilityNone) _SPIRV_OP(cl_khr_media_sharing, CapabilityNone) _SPIRV_OP(cl_khr_d3d11_sharing, CapabilityNone) _SPIRV_OP(cl_khr_global_int32_base_atomics, CapabilityNone) _SPIRV_OP(cl_khr_global_int32_extended_atomics, CapabilityNone) _SPIRV_OP(cl_khr_local_int32_base_atomics, CapabilityNone) _SPIRV_OP(cl_khr_local_int32_extended_atomics, CapabilityNone) _SPIRV_OP(cl_khr_byte_addressable_store, CapabilityNone) _SPIRV_OP(cl_khr_3d_image_writes, CapabilityImageReadWrite) _SPIRV_OP(cl_khr_gl_msaa_sharing, CapabilityNone) _SPIRV_OP(cl_khr_depth_images, CapabilityNone) _SPIRV_OP(cl_khr_gl_depth_images, CapabilityNone) _SPIRV_OP(cl_khr_subgroups, CapabilityGroups) _SPIRV_OP(cl_khr_mipmap_image, CapabilityImageMipmap) _SPIRV_OP(cl_khr_mipmap_image_writes, CapabilityImageMipmap) _SPIRV_OP(cl_khr_egl_event, CapabilityNone) _SPIRV_OP(cl_khr_srgb_image_writes, CapabilityImageSRGBWrite) #undef _SPIRV_OP }; /// \returns a vector of types for a collection of values. template std::vector getTypes(T V) { std::vector Tys; for (auto &I:V) Tys.push_back(I->getType()); return Tys; } void saveLLVMModule(Module *M, const std::string &OutputFile); PointerType *getOrCreateOpaquePtrType(Module *M, const std::string &Name, unsigned AddrSpace = SPIRAS_Global); void getFunctionTypeParameterTypes(llvm::FunctionType* FT, std::vector& ArgTys); Function *getOrCreateFunction(Module *M, Type *RetTy, ArrayRef ArgTypes, StringRef Name, bool Mangle = false, IGCLLVM::AttributeSet *Attrs = nullptr, bool takeName = true); std::vector getArguments(CallInst* CI); void decorateSPIRVBuiltin(std::string &S); void decorateSPIRVBuiltin(std::string &S, std::vector ArgTypes); void decorateSPIRVExtInst(std::string &S, std::vector ArgTypes); /// Check if a builtin function bool isFunctionBuiltin(llvm::Function* F); /// Get a canonical function name for a SPIR-V op code. std::string getSPIRVBuiltinName(Op OC, SPIRVInstruction *BI, std::vector ArgTypes, std::string suffix); /// Mutates function call instruction by changing the arguments. /// \param ArgMutate mutates the function arguments. /// \return mutated call instruction. CallInst *mutateCallInst(Module *M, CallInst *CI, std::function &)>ArgMutate, bool Mangle = false, IGCLLVM::AttributeSet *Attrs = nullptr, bool takeName = true); /// Mutate function by change the arguments. /// \param ArgMutate mutates the function arguments. void mutateFunction(Function *F, std::function &)>ArgMutate, bool Builtin , IGCLLVM::AttributeSet *Attrs = nullptr, bool takeName = true); /// Add a call instruction at \p Pos. CallInst *addCallInst(Module *M, StringRef FuncName, Type *RetTy, ArrayRef Args, IGCLLVM::AttributeSet *Attrs, Instruction *Pos, bool Builtin, StringRef InstName, bool TakeFuncName = true); /// Get a 64 bit integer constant. ConstantInt *getInt64(Module *M, int64_t value); /// Get a 32 bit integer constant. ConstantInt *getInt32(Module *M, int value); /// Decode OpenCL version which is encoded as Major*10^5+Minor*10^3+Rev std::tuple decodeOCLVer(unsigned Ver); } #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/SPIRVReader.cpp000066400000000000000000004037621363533017100252400ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVReader.cpp - Converts SPIR-V to LLVM -----------------*- C++ -*-===// // // The LLVM/SPIR-V Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements conversion of SPIR-V binary to LLVM IR. /// //===----------------------------------------------------------------------===// #include "common/LLVMWarningsPush.hpp" #include "llvmWrapper/IR/IRBuilder.h" #include "llvmWrapper/IR/DIBuilder.h" #include "llvmWrapper/IR/Module.h" #include "llvmWrapper/Support/Alignment.h" #include #include #include #include "libSPIRV/SPIRVDebugInfoExt.h" #include "llvm/Transforms/Utils/Cloning.h" #include "common/LLVMWarningsPop.hpp" #include "libSPIRV/SPIRVAsm.h" #include "llvm/IR/InlineAsm.h" #include "libSPIRV/SPIRVFunction.h" #include "libSPIRV/SPIRVInstruction.h" #include "libSPIRV/SPIRVModule.h" #include "SPIRVInternal.h" #include "common/MDFrameWork.h" #include "../../AdaptorCommon/TypesLegalizationPass.hpp" #include #include #include #include "Probe.h" using namespace llvm; namespace spv{ // Prefix for placeholder global variable name. const char* kPlaceholderPrefix = "placeholder."; #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) // Save the translated LLVM before validation for debugging purpose. static bool DbgSaveTmpLLVM = false; static const char *DbgTmpLLVMFileName = "_tmp_llvmspirv_module.ll"; #endif static bool isOpenCLKernel(SPIRVFunction *BF) { return BF->getModule()->isEntryPoint(ExecutionModelKernel, BF->getId()); } __attr_unused static void dumpLLVM(Module *M, const std::string &FName) { std::error_code EC; raw_fd_ostream FS(FName, EC, sys::fs::F_None); if (!FS.has_error()) { FS << *M; } FS.close(); } static MDNode* getMDNodeStringIntVec(LLVMContext *Context, llvm::StringRef Str, const std::vector& IntVals) { std::vector ValueVec; ValueVec.push_back(MDString::get(*Context, Str)); for (auto &I:IntVals) ValueVec.push_back(ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), I))); return MDNode::get(*Context, ValueVec); } static MDNode* getMDTwoInt(LLVMContext *Context, unsigned Int1, unsigned Int2) { std::vector ValueVec; ValueVec.push_back(ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), Int1))); ValueVec.push_back(ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), Int2))); return MDNode::get(*Context, ValueVec); } static MDNode* getMDString(LLVMContext *Context, llvm::StringRef Str) { std::vector ValueVec; if (!Str.empty()) ValueVec.push_back(MDString::get(*Context, Str)); return MDNode::get(*Context, ValueVec); } static void addOCLVersionMetadata(LLVMContext *Context, Module *M, llvm::StringRef MDName, unsigned Major, unsigned Minor) { NamedMDNode *NamedMD = M->getOrInsertNamedMetadata(MDName); NamedMD->addOperand(getMDTwoInt(Context, Major, Minor)); } static void addNamedMetadataString(LLVMContext *Context, Module *M, llvm::StringRef MDName, llvm::StringRef Str) { NamedMDNode *NamedMD = M->getOrInsertNamedMetadata(MDName); NamedMD->addOperand(getMDString(Context, Str)); } static void addOCLKernelArgumentMetadata(LLVMContext *Context, std::vector &KernelMD, llvm::StringRef MDName, SPIRVFunction *BF, std::functionFunc){ std::vector ValueVec; ValueVec.push_back(MDString::get(*Context, MDName)); BF->foreachArgument([&](SPIRVFunctionParameter *Arg) { ValueVec.push_back(Func(Arg)); }); KernelMD.push_back(MDNode::get(*Context, ValueVec)); } class SPIRVToLLVM; class SPIRVToLLVMDbgTran { public: SPIRVToLLVMDbgTran(SPIRVModule *TBM, Module *TM, SPIRVToLLVM* s) :BM(TBM), M(TM), SpDbg(BM), Builder(*M), SPIRVTranslator(s) { Enable = BM->hasDebugInfo(); } void addDbgInfoVersion() { if (!Enable) return; M->addModuleFlag(Module::Warning, "Dwarf Version", dwarf::DWARF_VERSION); M->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION); } DIFile *getDIFile(const std::string &FileName){ return getOrInsert(FileMap, FileName, [=](){ std::string BaseName; std::string Path; splitFileName(FileName, BaseName, Path); if (!BaseName.empty()) return Builder.createFile(BaseName, Path); else return Builder.createFile("", ""); }); } DIFile* getDIFile(SPIRVString* inst) { if (!inst) return nullptr; return getDIFile(inst->getStr()); } DIFile* getDIFile(SPIRVExtInst* inst) { OpDebugSource src(inst); return getDIFile(src.getFileStr()); } DICompileUnit* createCompileUnit() { if (!Enable || cu) return cu; OpCompilationUnit cunit(BM->getCompilationUnit()); auto lang = cunit.getLang(); auto file = getDIFile(BM->get(cunit.getSource())); auto producer = "spirv"; auto flags = ""; auto rv = 0; cu = Builder.createCompileUnit(lang, file, producer, false, flags, rv); addDbgInfoVersion(); return addMDNode(BM->getCompilationUnit(), cu); } DIExpression* createExpression(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; return addMDNode(inst, Builder.createExpression()); } DIType* createTypeBasic(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeBasic type(inst); uint64_t sizeInBits = type.getSize(); unsigned int encoding; auto enc = type.getEncoding(); auto& name = type.getName()->getStr(); switch (enc) { case SPIRVDebug::EncodingTag::Boolean: encoding = dwarf::DW_ATE_boolean; break; case SPIRVDebug::EncodingTag::Address: encoding = dwarf::DW_ATE_address; break; case SPIRVDebug::EncodingTag::Float: encoding = dwarf::DW_ATE_float; break; case SPIRVDebug::EncodingTag::Signed: encoding = dwarf::DW_ATE_signed; break; case SPIRVDebug::EncodingTag::Unsigned: encoding = dwarf::DW_ATE_unsigned; break; case SPIRVDebug::EncodingTag::SignedChar: encoding = dwarf::DW_ATE_signed_char; break; case SPIRVDebug::EncodingTag::UnsignedChar: encoding = dwarf::DW_ATE_unsigned_char; break; default: return addMDNode(inst, Builder.createUnspecifiedType(name)); } return addMDNode(inst, Builder.createBasicType(name, sizeInBits, encoding)); } DIType* createPtrType(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugPtrType ptrType(inst); auto pointeeType = createType(BM->get(ptrType.getBaseType())); return addMDNode(inst, Builder.createPointerType(pointeeType, M->getDataLayout().getPointerSizeInBits())); } DIType* createTypeQualifier(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeQualifier qualType(inst); auto baseType = createType(BM->get(qualType.getBaseType())); auto qual = qualType.getQualifier(); unsigned int qualifier = 0; if (qual == OpDebugTypeQualifier::TypeQualifier::qual_const) qualifier = dwarf::DW_TAG_const_type; else if (qual == OpDebugTypeQualifier::TypeQualifier::qual_restrict) qualifier = dwarf::DW_TAG_restrict_type; else if (qual == OpDebugTypeQualifier::TypeQualifier::qual_volatile) qualifier = dwarf::DW_TAG_volatile_type; return addMDNode(inst, Builder.createQualifiedType(qualifier, baseType)); } DIType* createTypeArray(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeArray arrayType(inst); auto baseType = createType(BM->get(arrayType.getBaseType())); auto numDims = arrayType.getNumDims(); SmallVector subscripts; uint64_t totalCount = 1; for (unsigned int i = 0; i != numDims; i++) { auto val = BM->get(arrayType.getComponentCount(i))->getZExtIntValue(); subscripts.push_back(Builder.getOrCreateSubrange(0, val)); totalCount *= (uint64_t)(val); } DINodeArray subscriptArray = Builder.getOrCreateArray(subscripts); return addMDNode(inst, Builder.createArrayType(totalCount * baseType->getSizeInBits(), 0, baseType, subscriptArray)); } DIType* createTypeVector(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeVector vectorType(inst); auto size = vectorType.getNumComponents(); auto type = createType(BM->get(vectorType.getBaseType())); SmallVector subscripts; subscripts.push_back(Builder.getOrCreateSubrange(0, size)); DINodeArray subscriptArray = Builder.getOrCreateArray(subscripts); return addMDNode(inst, Builder.createVectorType(size * type->getSizeInBits(), 0, type, subscriptArray)); } DIType* createTypeDef(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeDef typeDef(inst); auto type = createType(BM->get(typeDef.getBaseType())); auto& name = typeDef.getName()->getStr(); auto file = getDIFile(BM->get(typeDef.getSource())); auto line = typeDef.getLine(); auto scopeContext = createScope(BM->get(typeDef.getParent())); return addMDNode(inst, Builder.createTypedef(type, name, file, line, scopeContext)); } DIType* createTypeEnum(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeEnum typeEnum(inst); auto scope = createScope(BM->get(typeEnum.getParent())); auto& name = typeEnum.getName()->getStr(); auto file = getDIFile(BM->get(typeEnum.getSource())); auto line = typeEnum.getLine(); auto size = typeEnum.getSize(); auto type = createType(BM->get(typeEnum.getType())); SmallVector elements; for (unsigned int i = 0; i != typeEnum.getNumItems(); i++) { auto item = typeEnum.getItem(i); auto enumerator = Builder.createEnumerator(item.first->getStr(), item.second); elements.push_back(enumerator); } auto nodeArray = Builder.getOrCreateArray(llvm::makeArrayRef(elements)); return addMDNode(inst, Builder.createEnumerationType(scope, name, file, line, size, 0, nodeArray, type)); } DIType* createMember(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeMember typeMember(inst); // scope is not clear from SPIRV spec auto scope = getCompileUnit(); auto& name = typeMember.getName()->getStr(); auto file = getDIFile(BM->get(typeMember.getSource())); auto line = typeMember.getLine(); auto size = typeMember.getSize(); auto offset = typeMember.getOffset(); auto flagRaw = typeMember.getFlags(); auto type = createType(BM->get(typeMember.getType())); return addMDNode(inst, Builder.createMemberType(scope, name, file, line, size, 0, offset, (llvm::DINode::DIFlags) flagRaw, type)); } DIType* createCompositeType(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeComposite compositeType(inst); auto tag = compositeType.getTag(); auto& name = compositeType.getName()->getStr(); auto file = getDIFile(BM->get(compositeType.getSource())); auto line = compositeType.getLine(); auto size = compositeType.getSize(); auto flagRaw = compositeType.getFlags(); auto scope = createScope(BM->get(compositeType.getParent())); if (!scope) scope = cu; #if 0 // SPIRV spec has single parent field whereas LLVM DIBuilder API requires Scope as well as DerivedFrom. // What is expected behavior? // parent may be OpDebugCompilationUnit/OpDebugFunction/OpDebugLexicalBlock/OpDebugTypeComposite DIType* from = nullptr; auto parentInst = BM->get(parent); if (parentInst->getExtOp() == OCLExtOpDbgKind::CompileUnit) from = nullptr; else if (parentInst->getExtOp() == OCLExtOpDbgKind::Function) from = nullptr;//createFunction(parentInst); else if (parentInst->getExtOp() == OCLExtOpDbgKind::LexicalBlock) from = nullptr; //createLexicalBlock(parentInst); else if (parentInst->getExtOp() == OCLExtOpDbgKind::TypeComposite) from = createCompositeType(parentInst); #endif DIType* derivedFrom = nullptr; DICompositeType* newNode = nullptr; if (tag == SPIRVDebug::CompositeTypeTag::Structure) { newNode = addMDNode(inst, Builder.createStructType(scope, name, file, line, size, 0, (llvm::DINode::DIFlags)flagRaw, derivedFrom, DINodeArray())); } else if (tag == SPIRVDebug::CompositeTypeTag::Union) { newNode = addMDNode(inst, Builder.createUnionType(scope, name, file, line, size, 0, (llvm::DINode::DIFlags)flagRaw, DINodeArray())); } else if (tag == SPIRVDebug::CompositeTypeTag::Class) { newNode = addMDNode(inst, Builder.createClassType(scope, name, file, line, size, 0, 0, (llvm::DINode::DIFlags)flagRaw, derivedFrom, DINodeArray())); } SmallVector elements; for (unsigned int i = 0; i != compositeType.getNumItems(); i++) { auto member = static_cast(BM->getEntry(compositeType.getItem(i))); if (member->getExtOp() == OCLExtOpDbgKind::TypeMember) { auto md = createMember(member); elements.push_back(md); } else if (member->getExtOp() == OCLExtOpDbgKind::TypeInheritance) { elements.push_back(createTypeInherit(member)); } else if (member->getExtOp() == OCLExtOpDbgKind::FuncDecl) { elements.push_back(createFunctionDecl(member)); } } DINodeArray Elements = Builder.getOrCreateArray(elements); Builder.replaceArrays(newNode, Elements); return newNode; } DIType* createTypeInherit(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeInheritance typeInherit(inst); auto type = createType(BM->get(typeInherit.getChild())); auto base = createType(BM->get(typeInherit.getParent())); auto offset = typeInherit.getOffset(); auto flagRaw = typeInherit.getFlags(); return addMDNode(inst, Builder.createInheritance(type, base, offset, (llvm::DINode::DIFlags)flagRaw)); } DIType* createPtrToMember(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugPtrToMember ptrToMember(inst); auto pointee = createType(BM->get(ptrToMember.getType())); auto Class = createType(BM->get(ptrToMember.getParent())); auto size = M->getDataLayout().getPointerSizeInBits(); return addMDNode(inst, Builder.createMemberPointerType(pointee, Class, size)); } DITemplateParameter* createTemplateParm(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; auto templateOp = inst->getExtOp(); if (templateOp == OCLExtOpDbgKind::TypeTemplateParameter) { OpDebugTypeTemplateParm parm(inst); auto actualType = createType(BM->get(parm.getActualType())); if (!parm.hasValue()) { return addMDNode(inst, Builder.createTemplateTypeParameter(cu, parm.getName()->getStr(), actualType)); } else { auto val = parm.getValue(); auto constant = ConstantInt::get(Type::getInt64Ty(M->getContext()), val); return addMDNode(inst, Builder.createTemplateValueParameter(cu, parm.getName()->getStr(), actualType, constant)); } } else if (templateOp == OCLExtOpDbgKind::TypeTemplateTemplateParameter) { OpDebugTypeTemplateParmPack parmPack(inst); auto& name = parmPack.getName()->getStr(); SmallVector Elts; for (unsigned int i = 0; i != parmPack.getNumParms(); i++) { Elts.push_back(createTemplateParm(BM->get(parmPack.getParm(i)))); } DINodeArray pack = Builder.getOrCreateArray(Elts); return addMDNode(inst, Builder.createTemplateParameterPack(cu, name, nullptr, pack)); } else if (templateOp == OCLExtOpDbgKind::TypeTemplateParameterPack) { OpDebugTypeTemplateTemplateParm tempTempParm(inst); auto& name = tempTempParm.getName()->getStr(); auto& templName = tempTempParm.getTemplateName()->getStr(); return addMDNode(inst, Builder.createTemplateTemplateParameter(cu, name, nullptr, templName)); } return nullptr; } MDNode* createTypeTemplate(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugTypeTemplate typeTemplate(inst); auto target = createType(BM->get(typeTemplate.getTarget())); SmallVector Elts; for (unsigned int i = 0; i != typeTemplate.getNumParms(); i++) { auto parm = BM->get(typeTemplate.getParm(i)); Elts.push_back(createTemplateParm(parm)); } DINodeArray TParams = Builder.getOrCreateArray(Elts); if (DICompositeType *Comp = dyn_cast(target)) { Builder.replaceArrays(Comp, Comp->getElements(), TParams); return Comp; } if (isa(target)) { // This constant matches with one used in // DISubprogram::getRawTemplateParams() #if LLVM_VERSION_MAJOR == 4 const unsigned TemplateParamsIndex = 8; #elif LLVM_VERSION_MAJOR >= 7 const unsigned TemplateParamsIndex = 9; #endif target->replaceOperandWith(TemplateParamsIndex, TParams.get()); IGC_ASSERT(cast(target)->getRawTemplateParams() == TParams.get() && "Invalid template parameters"); return target; } return nullptr; } DIType* createType(SPIRVExtInst* type) { if (!type) { // return void type return Builder.createNullPtrType(); } if (auto n = getExistingNode(type)) return n; switch (type->getExtOp()) { case OCLExtOpDbgKind::TypeBasic: return createTypeBasic(type); case OCLExtOpDbgKind::TypePtr: return createPtrType(type); case OCLExtOpDbgKind::TypeComposite: return createCompositeType(type); case OCLExtOpDbgKind::TypeQualifier: return createTypeQualifier(type); case OCLExtOpDbgKind::TypeArray: return createTypeArray(type); case OCLExtOpDbgKind::TypeVector: return createTypeVector(type); case OCLExtOpDbgKind::TypeDef: return createTypeDef(type); case OCLExtOpDbgKind::TypeEnum: return createTypeEnum(type); case OCLExtOpDbgKind::TypeInheritance: return createTypeInherit(type); case OCLExtOpDbgKind::TypePtrToMember: return createPtrToMember(type); case OCLExtOpDbgKind::TypeFunction: return createSubroutineType(type); case OCLExtOpDbgKind::TypeTemplate: return (DIType*)createTypeTemplate(type); case OCLExtOpDbgKind::Function: return (DIType*)createFunction(type); default: break; } return addMDNode(type, Builder.createBasicType("int", 4, 0)); } DIGlobalVariable* createGlobalVariable(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugGlobalVar globalVar(inst); auto& name = globalVar.getName()->getStr(); auto& linkageName = globalVar.getLinkageName()->getStr(); auto file = getDIFile(BM->get(globalVar.getSource())); auto line = globalVar.getLine(); auto type = createType(BM->get(globalVar.getType())); return addMDNode(inst, Builder.createTempGlobalVariableFwdDecl(getCompileUnit(), name, linkageName, file, (unsigned int)line, type, true)); } DISubprogram* createFunctionDecl(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugFuncDecl funcDcl(inst); auto scope = createScope(BM->get(funcDcl.getParent())); auto& name = funcDcl.getName()->getStr(); auto& linkageName = funcDcl.getLinkageName()->getStr(); auto file = getDIFile(BM->get(funcDcl.getSource())); auto line = funcDcl.getLine(); auto type = createSubroutineType(BM->get(funcDcl.getType())); if (isa(scope) || isa(scope)) return addMDNode(inst, Builder.createMethod(scope, name, linkageName, file, line, type, true, true)); else return addMDNode(inst, Builder.createTempFunctionFwdDecl(scope, name, linkageName, file, (unsigned int)line, type, true, true, (unsigned int)line)); } bool isTemplateType(SPIRVExtInst* inst) { return (inst->getExtOp() == OCLExtOpDbgKind::TypeTemplate); } DISubroutineType* createSubroutineType(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugSubroutineType spType(inst); std::vector Args; auto returnType = BM->getEntry(spType.getReturnType()); if(returnType->getOpCode() == Op::OpTypeVoid) Args.push_back(nullptr); else Args.push_back(createType(BM->get(spType.getReturnType()))); for (unsigned int i = 0; i != spType.getNumParms(); i++) { auto parmType = spType.getParmType(i); if (!isTemplateType(static_cast(BM->getValue(parmType)))) Args.push_back(createType(static_cast(BM->getValue(parmType)))); else Args.push_back(createTypeTemplate(static_cast(BM->getValue(parmType)))); } return addMDNode(inst, Builder.createSubroutineType(Builder.getOrCreateTypeArray(Args))); } bool isDebugInfoNone(SPIRVId id) { auto entry = BM->get(id); if (entry) { if (entry->getExtOp() == OCLExtOpDbgKind::DebugInfoNone) return true; } return false; } DISubprogram* createFunction(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugSubprogram sp(inst); auto scope = createScope(BM->get(sp.getParent())); auto& name = sp.getName()->getStr(); auto& linkageName = sp.getLinkage()->getStr(); auto file = getDIFile(BM->get(sp.getSource())); auto spType = createSubroutineType(BM->get(sp.getType())); auto flags = (DINode::DIFlags)(sp.getFlags()); bool isDefinition = (SPIRVWord)flags & SPIRVDebug::FlagIsDefinition; bool isOptimized = (SPIRVWord)flags & SPIRVDebug::FlagIsOptimized; bool isLocal = (SPIRVWord)flags & SPIRVDebug::FlagIsLocal; auto funcSPIRVId = sp.getSPIRVFunction(); SmallVector Elts; DINodeArray TParams = Builder.getOrCreateArray(Elts); llvm::DITemplateParameterArray TParamsArray = TParams.get(); DISubprogram* diSP = nullptr; if ((isa(scope) || isa(scope)) && !isDefinition) { diSP = Builder.createMethod(scope, name, linkageName, file, sp.getLine(), spType, isLocal, isDefinition, 0, 0, 0, nullptr, flags, isOptimized, TParamsArray); } else { diSP = Builder.createFunction(scope, name, linkageName, file, sp.getLine(), spType, isLocal, isDefinition, sp.getScopeLine(), flags, isOptimized, TParamsArray); } FuncIDToDISP[funcSPIRVId] = diSP; return addMDNode(inst, diSP); } DIScope* createLexicalBlock(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugLexicalBlock lb(inst); auto scope = createScope(BM->get(lb.getParent())); auto file = getDIFile(BM->get(lb.getSource())); if (!scope || isa(scope)) return nullptr; if(lb.hasNameSpace() || isa(scope)) return addMDNode(inst, Builder.createNameSpace(scope, lb.getNameSpace()->getStr(), file, lb.getLine(), false)); return addMDNode(inst, Builder.createLexicalBlock(scope, file, lb.getLine(), lb.getColumn())); } DILexicalBlockFile* createLexicalBlockDiscriminator(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugLexicalBlkDiscriminator lbDisc(inst); auto scope = createScope(BM->get(lbDisc.getParent())); auto file = getDIFile(BM->get(lbDisc.getSource())); auto disc = lbDisc.getDiscriminator(); return addMDNode(inst, Builder.createLexicalBlockFile(scope, file, disc)); } DILocation* createInlinedAt(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugInlinedAt inlinedAt(inst); DILocation* iat = nullptr; auto line = inlinedAt.getLine(); auto scope = createScope(BM->get(inlinedAt.getScope())); if(inlinedAt.inlinedAtPresent()) iat = createInlinedAt(BM->get(inlinedAt.getInlinedAt())); return addMDNode(inst, createLocation(line, 0, scope, iat)); } DIScope* createScope(SPIRVExtInst* inst) { if (!inst) return nullptr; if (inst->isString()) { // Treat inst as a SPIRVInstruction instead of SPIRVExtInst // This is a WA since SPIRV emitter emits OpString as // scope of DebugFunction ext opcode. return getDIFile(((SPIRVString*)inst)->getStr()); } if (inst->getExtOp() == OCLExtOpDbgKind::Scope) { OpDebugScope scope(inst); return createScope(BM->get(scope.getScope())); } if (inst->getExtOp() == OCLExtOpDbgKind::Function) { return createFunction(inst); } else if (inst->getExtOp() == OCLExtOpDbgKind::LexicalBlock) { return createLexicalBlock(inst); } else if (inst->getExtOp() == OCLExtOpDbgKind::LexicalBlockDiscriminator) { return createLexicalBlockDiscriminator(inst); } else if (inst->getExtOp() == OCLExtOpDbgKind::CompileUnit) { return createCompileUnit(); } else if (inst->getExtOp() == OCLExtOpDbgKind::TypeComposite) { return createCompositeType(inst); } else if (inst->getExtOp() == OCLExtOpDbgKind::TypeTemplate) { return (DIScope*)createTypeTemplate(inst); } else { return getDIFile("unexpected path in getScope()"); } return nullptr; } DILocation* getInlinedAtFromScope(SPIRVExtInst* inst) { if (inst->getExtOp() == OCLExtOpDbgKind::Scope) { OpDebugScope scope(inst); if (!scope.hasInlinedAt()) return nullptr; return createInlinedAt(BM->get(scope.getInlinedAt())); } return nullptr; } DILocalVariable* createInlinedLocalVar(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugInlinedLocalVar var(inst); auto origVar = createLocalVar(BM->get(var.getVar())); //auto inlinedAt = createInlinedAt(BM->get(var.getInlinedAt())); return addMDNode(inst, origVar); } DILocalVariable* createLocalVar(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugLocalVar var(inst); auto scope = createScope(BM->get(var.getParent())); auto& name = BM->get(var.getName())->getStr(); auto file = getDIFile(BM->get(var.getSource())); auto type = createType(BM->get(var.getType())); auto line = var.getLine(); if (var.isParamVar()) { return addMDNode(inst, Builder.createParameterVariable(scope, name, var.getArgNo(), file, line, type)); } else { return addMDNode(inst, Builder.createAutoVariable(scope, name, file, line, type)); } } DIGlobalVariableExpression* createGlobalVar(SPIRVExtInst* inst); DILocation* createLocation(SPIRVWord line, SPIRVWord column, DIScope* scope, DILocation* inlinedAt = nullptr) { if (scope && isa(scope)) return nullptr; return DILocation::get(M->getContext(), (unsigned int)line, (unsigned int)column, scope, inlinedAt); } Instruction* createDbgDeclare(SPIRVExtInst* inst, Value* localVar, BasicBlock* insertAtEnd) { // Format // 8 12 Result Type Result Set 28 Local Variable Variable Expression OpDebugDeclare dbgDcl(inst); auto scope = createScope(inst->getDIScope()); auto iat = getInlinedAtFromScope(inst->getDIScope()); if (!scope) return nullptr; auto dbgDclInst = Builder.insertDeclare(localVar, createLocalVar(BM->get(dbgDcl.getVar())), createExpression(BM->get(dbgDcl.getExpression())), createLocation(inst->getLine()->getLine(), inst->getLine()->getColumn(), scope, iat), insertAtEnd); return dbgDclInst; } Instruction* createDbgValue(SPIRVExtInst* inst, Value* localVar, BasicBlock* insertAtEnd) { OpDebugValue dbgValue(inst); auto scope = createScope(inst->getDIScope()); auto iat = getInlinedAtFromScope(inst->getDIScope()); if (!scope) return nullptr; auto dbgValueInst = Builder.insertDbgValueIntrinsic(localVar, 0, createLocalVar(BM->get(dbgValue.getVar())), createExpression(BM->get(dbgValue.getExpression())), createLocation(inst->getLine()->getLine(), inst->getLine()->getColumn(), scope, iat), insertAtEnd); return dbgValueInst; } void transGlobals() { if (!Enable) return; auto globalVars = BM->getGlobalVars(); for (auto& gvar : globalVars) { (void)createGlobalVar(gvar); } } void transDbgInfo(SPIRVValue *SV, Value *V); void finalize() { if (!Enable) return; Builder.finalize(); } template T getExistingNode(SPIRVInstruction* inst) { auto it = MDMap.find(inst); if (it != MDMap.end()) return (T)it->second; return nullptr; } template T addMDNode(SPIRVInstruction* inst, T node) { MDMap[inst] = node; return node; } DISubprogram* getDISP(SPIRVId id) { auto it = FuncIDToDISP.find(id); if (it != FuncIDToDISP.end()) return (*it).second; return nullptr; } private: SPIRVModule *BM; Module *M; SPIRVDbgInfo SpDbg; IGCLLVM::DIBuilder Builder; bool Enable; DICompileUnit* cu = nullptr; SPIRVToLLVM* SPIRVTranslator = nullptr; std::unordered_map FileMap; std::unordered_map FuncMap; std::unordered_map MDMap; std::unordered_map FuncIDToDISP; DICompileUnit* getCompileUnit() { return cu; } void splitFileName(const std::string &FileName, std::string &BaseName, std::string &Path) { auto Loc = FileName.find_last_of("/\\"); if (Loc != std::string::npos) { BaseName = FileName.substr(Loc + 1); Path = FileName.substr(0, Loc); } else { BaseName = FileName; Path = "."; } } }; class SPIRVToLLVM { public: SPIRVToLLVM(Module *LLVMModule, SPIRVModule *TheSPIRVModule) :M((IGCLLVM::Module*)LLVMModule), BM(TheSPIRVModule), DbgTran(BM, M, this){ if (M) Context = &M->getContext(); else Context = NULL; } Type *transType(SPIRVType *BT); GlobalValue::LinkageTypes transLinkageType(const SPIRVValue* V); /// Decode SPIR-V encoding of vector type hint execution mode. Type *decodeVecTypeHint(LLVMContext &C, unsigned code); std::string transTypeToOCLTypeName(SPIRVType *BT, bool IsSigned = true); std::vector transTypeVector(const std::vector&); bool translate(); bool transAddressingModel(); enum class BoolAction { Promote, Truncate, Noop }; Value *transValue(SPIRVValue *, Function *F, BasicBlock *, bool CreatePlaceHolder = true, BoolAction Action = BoolAction::Promote); Value *transValueWithoutDecoration(SPIRVValue *, Function *F, BasicBlock *, bool CreatePlaceHolder); bool transDecoration(SPIRVValue *, Value *); bool transAlign(SPIRVValue *, Value *); Instruction *transOCLBuiltinFromExtInst(SPIRVExtInst *BC, BasicBlock *BB); std::vector transValue(const std::vector&, Function *F, BasicBlock *, BoolAction Action = BoolAction::Promote); Function *transFunction(SPIRVFunction *F); bool transFPContractMetadata(); bool transKernelMetadata(); bool transSourceLanguage(); bool transSourceExtension(); /*InlineAsm*/ Value *transAsmINTEL(SPIRVAsmINTEL *BA, Function *F, BasicBlock *BB); CallInst *transAsmCallINTEL(SPIRVAsmCallINTEL *BI, Function *F, BasicBlock *BB); Type* m_NamedBarrierType = nullptr; Type* getNamedBarrierType(); Value *transConvertInst(SPIRVValue* BV, Function* F, BasicBlock* BB); Instruction *transSPIRVBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB); void transOCLVectorLoadStore(std::string& UnmangledName, std::vector &BArgs); /// Post-process translated LLVM module for OpenCL. bool postProcessOCL(); Instruction* transDebugInfo(SPIRVExtInst*, llvm::BasicBlock*); SPIRVToLLVMDbgTran& getDbgTran() { return DbgTran; } /// \brief Post-process OpenCL builtin functions returning struct type. /// /// Some OpenCL builtin functions are translated to SPIR-V instructions with /// struct type result, e.g. NDRange creation functions. Such functions /// need to be post-processed to return the struct through sret argument. bool postProcessFunctionsReturnStruct(Function *F); /// \brief Post-process OpenCL builtin functions having aggregate argument. /// /// These functions are translated to functions with aggregate type argument /// first, then post-processed to have pointer arguments. bool postProcessFunctionsWithAggregateArguments(Function *F); typedef DenseMap SPIRVToLLVMTypeMap; typedef DenseMap SPIRVToLLVMValueMap; typedef DenseMap SPIRVToLLVMFunctionMap; typedef DenseMap BuiltinVarMap; // A SPIRV value may be translated to a load instruction of a placeholder // global variable. This map records load instruction of these placeholders // which are supposed to be replaced by the real values later. typedef std::map SPIRVToLLVMPlaceholderMap; Value *getTranslatedValue(SPIRVValue *BV); private: IGCLLVM::Module *M; BuiltinVarMap BuiltinGVMap; LLVMContext *Context; SPIRVModule *BM; SPIRVToLLVMTypeMap TypeMap; SPIRVToLLVMValueMap ValueMap; SPIRVToLLVMFunctionMap FuncMap; SPIRVToLLVMPlaceholderMap PlaceholderMap; SPIRVToLLVMDbgTran DbgTran; GlobalVariable *m_NamedBarrierVar; GlobalVariable *m_named_barrier_id; DICompileUnit* compileUnit = nullptr; Type *mapType(SPIRVType *BT, Type *T) { TypeMap[BT] = T; return T; } // If a value is mapped twice, the existing mapped value is a placeholder, // which must be a load instruction of a global variable whose name starts // with kPlaceholderPrefix. Value *mapValue(SPIRVValue *BV, Value *V) { auto Loc = ValueMap.find(BV); if (Loc != ValueMap.end()) { if (Loc->second == V) return V; auto LD = dyn_cast(Loc->second); auto Placeholder = dyn_cast(LD->getPointerOperand()); IGC_ASSERT_EXIT(LD && Placeholder && Placeholder->getName().startswith(kPlaceholderPrefix) && "A value is translated twice"); // Replaces placeholders for PHI nodes LD->replaceAllUsesWith(V); LD->eraseFromParent(); Placeholder->eraseFromParent(); } ValueMap[BV] = V; return V; } bool isSPIRVBuiltinVariable(GlobalVariable *GV, SPIRVBuiltinVariableKind *Kind = nullptr) { auto Loc = BuiltinGVMap.find(GV); if (Loc == BuiltinGVMap.end()) return false; if (Kind) *Kind = Loc->second; return true; } // OpenCL function always has NoUnwound attribute. // Change this if it is no longer true. bool isFuncNoUnwind() const { return true;} bool isSPIRVCmpInstTransToLLVMInst(SPIRVInstruction *BI) const; bool transOCLBuiltinsFromVariables(); bool transOCLBuiltinFromVariable(GlobalVariable *GV, SPIRVBuiltinVariableKind Kind); MDString *transOCLKernelArgTypeName(SPIRVFunctionParameter *); Value *mapFunction(SPIRVFunction *BF, Function *F) { FuncMap[BF] = F; return F; } Type *getTranslatedType(SPIRVType *BT); SPIRVErrorLog &getErrorLog() { return BM->getErrorLog(); } void setCallingConv(CallInst *Call) { Function *F = Call->getCalledFunction(); Call->setCallingConv(F->getCallingConv()); } void setAttrByCalledFunc(CallInst *Call); Type *transFPType(SPIRVType* T); BinaryOperator *transShiftLogicalBitwiseInst(SPIRVValue* BV, BasicBlock* BB, Function* F); Instruction *transCmpInst(SPIRVValue* BV, BasicBlock* BB, Function* F); Instruction *transLifetimeInst(SPIRVInstTemplateBase* BV, BasicBlock* BB, Function* F); uint64_t calcImageType(const SPIRVValue *ImageVal); std::string transOCLImageTypeName(spv::SPIRVTypeImage* ST); std::string transOCLSampledImageTypeName(spv::SPIRVTypeSampledImage* ST); std::string transOCLImageTypeAccessQualifier(spv::SPIRVTypeImage* ST); std::string transOCLPipeTypeAccessQualifier(spv::SPIRVTypePipe* ST); Value *oclTransConstantSampler(spv::SPIRVConstantSampler* BCS); template bool foreachFuncCtlMask(Source, Func); void setLLVMLoopMetadata(SPIRVLoopMerge* LM, BranchInst* BI); inline llvm::Metadata *getMetadataFromName(std::string Name); inline std::vector getMetadataFromNameAndParameter(std::string Name, SPIRVWord Parameter); Value *promoteBool(Value *pVal, BasicBlock *BB); Value *truncBool(Value *pVal, BasicBlock *BB); Type *truncBoolType(SPIRVType *SPVType, Type *LLType); }; DIGlobalVariableExpression* SPIRVToLLVMDbgTran::createGlobalVar(SPIRVExtInst* inst) { if (auto n = getExistingNode(inst)) return n; OpDebugGlobalVar var(inst); auto ctxt = createScope(BM->get(var.getParent())); auto& name = var.getName()->getStr(); auto& linkageName = var.getLinkageName()->getStr(); auto file = getDIFile(BM->get(var.getSource())); auto type = createType(BM->get(var.getType())); auto varValue = static_cast(BM->getEntry(var.getVariable())); auto globalVarMD = addMDNode(inst, Builder.createGlobalVariableExpression(ctxt, name, linkageName, file, var.getLine(), type, true)); llvm::Value* llvmValue = nullptr; if (varValue) { llvmValue = SPIRVTranslator->getTranslatedValue(varValue); if (llvmValue && dyn_cast_or_null(llvmValue)) { dyn_cast(llvmValue)->addDebugInfo(globalVarMD); } } return globalVarMD; } void SPIRVToLLVMDbgTran::transDbgInfo(SPIRVValue *SV, Value *V) { if (!SV) return; if (!Enable || !SV->hasLine() || !SV->getDIScope()) return; if (auto I = dyn_cast(V)) { IGC_ASSERT(SV->isInst() && "Invalid instruction"); auto SI = static_cast(SV); IGC_ASSERT(SI->getParent() && SI->getParent()->getParent() && "Invalid instruction"); auto Line = SV->getLine(); DILocation* iat = nullptr; DIScope* scope = nullptr; if (SV->getDIScope()) { scope = SPIRVTranslator->getDbgTran().createScope(SV->getDIScope()); iat = SPIRVTranslator->getDbgTran().getInlinedAtFromScope(SV->getDIScope()); } SPIRVTranslator->getDbgTran().createLocation(Line->getLine(), Line->getColumn(), scope, iat); if(scope && !isa(scope)) I->setDebugLoc(DebugLoc::get(Line->getLine(), Line->getColumn(), scope, iat)); } } Type * SPIRVToLLVM::getTranslatedType(SPIRVType *BV){ auto Loc = TypeMap.find(BV); if (Loc != TypeMap.end()) return Loc->second; return nullptr; } Value * SPIRVToLLVM::getTranslatedValue(SPIRVValue *BV){ auto Loc = ValueMap.find(BV); if (Loc != ValueMap.end()) return Loc->second; return nullptr; } void SPIRVToLLVM::setAttrByCalledFunc(CallInst *Call) { Function *F = Call->getCalledFunction(); if (F->isIntrinsic()) { return; } Call->setCallingConv(F->getCallingConv()); Call->setAttributes(F->getAttributes()); } SPIRAddressSpace getOCLOpaqueTypeAddrSpace(Op OpCode) { switch (OpCode) { case OpTypePipe: // these types are handled in special way at SPIRVToLLVM::transType return SPIRAS_Global; default: //OpTypeQueue: //OpTypeEvent: //OpTypeDeviceEvent: //OpTypeReserveId return SPIRAS_Private; } } bool SPIRVToLLVM::transOCLBuiltinsFromVariables(){ std::vector WorkList; for (auto I = M->global_begin(), E = M->global_end(); I != E; ++I) { SPIRVBuiltinVariableKind Kind = BuiltInCount; if (!isSPIRVBuiltinVariable(&(*I), &Kind)) continue; if (!transOCLBuiltinFromVariable(&(*I), Kind)) return false; WorkList.push_back(&(*I)); } for (auto &I:WorkList) { I->eraseFromParent(); } return true; } // For integer types shorter than 32 bit, unsigned/signedness can be inferred // from zext/sext attribute. MDString * SPIRVToLLVM::transOCLKernelArgTypeName(SPIRVFunctionParameter *Arg) { auto Ty = Arg->isByVal() ? Arg->getType()->getPointerElementType() : Arg->getType(); return MDString::get(*Context, transTypeToOCLTypeName(Ty, !Arg->isZext())); } // Variable like GlobalInvocationId[x] -> get_global_id(x). // Variable like WorkDim -> get_work_dim(). bool SPIRVToLLVM::transOCLBuiltinFromVariable(GlobalVariable *GV, SPIRVBuiltinVariableKind Kind) { std::string FuncName; if (!SPIRSPIRVBuiltinVariableMap::find(Kind, &FuncName)) return false; decorateSPIRVBuiltin(FuncName); Function *Func = M->getFunction(FuncName); if (!Func) { Type *ReturnTy = GV->getType()->getPointerElementType(); FunctionType *FT = FunctionType::get(ReturnTy, false); Func = Function::Create(FT, GlobalValue::ExternalLinkage, FuncName, M); Func->setCallingConv(CallingConv::SPIR_FUNC); Func->addFnAttr(Attribute::NoUnwind); Func->addFnAttr(Attribute::ReadNone); } SmallVector Deletes; SmallVector Users; for (auto UI : GV->users()) { LoadInst *LD = nullptr; AddrSpaceCastInst* ASCast = dyn_cast(&*UI); if (ASCast) { LD = cast(*ASCast->user_begin()); } else { LD = cast(&*UI); } Users.push_back(LD); Deletes.push_back(LD); if (ASCast) Deletes.push_back(ASCast); } for (auto &I : Users) { auto Call = CallInst::Create(Func, "", I); Call->takeName(I); setAttrByCalledFunc(Call); I->replaceAllUsesWith(Call); } for (auto &I : Deletes) { IGC_ASSERT(I->use_empty()); if (I->use_empty()) I->eraseFromParent(); } return true; } Type * SPIRVToLLVM::transFPType(SPIRVType* T) { switch(T->getFloatBitWidth()) { case 16: return Type::getHalfTy(*Context); case 32: return Type::getFloatTy(*Context); case 64: return Type::getDoubleTy(*Context); default: llvm_unreachable("Invalid type"); return nullptr; } } std::string SPIRVToLLVM::transOCLImageTypeName(spv::SPIRVTypeImage* ST) { return std::string(kSPR2TypeName::OCLPrefix) + rmap(ST->getDescriptor()) + kSPR2TypeName::Delimiter + rmap(ST->getAccessQualifier()); } std::string SPIRVToLLVM::transOCLSampledImageTypeName(spv::SPIRVTypeSampledImage* ST) { return std::string(kLLVMName::builtinPrefix) + kSPIRVTypeName::SampledImage; } inline llvm::Metadata *SPIRVToLLVM::getMetadataFromName(std::string Name) { return llvm::MDNode::get(*Context, llvm::MDString::get(*Context, Name)); } inline std::vector SPIRVToLLVM::getMetadataFromNameAndParameter(std::string Name, SPIRVWord Parameter) { return {MDString::get(*Context, Name), ConstantAsMetadata::get( ConstantInt::get(Type::getInt32Ty(*Context), Parameter))}; } void SPIRVToLLVM::setLLVMLoopMetadata(SPIRVLoopMerge *LM, BranchInst *BI) { if (!LM) return; auto Temp = MDNode::getTemporary(*Context, None); auto Self = MDNode::get(*Context, Temp.get()); Self->replaceOperandWith(0, Self); SPIRVWord LC = LM->getLoopControl(); if (LC == LoopControlMaskNone) { BI->setMetadata("llvm.loop", Self); return; } unsigned NumParam = 0; std::vector Metadata; std::vector LoopControlParameters = LM->getLoopControlParameters(); Metadata.push_back(llvm::MDNode::get(*Context, Self)); // To correctly decode loop control parameters, order of checks for loop // control masks must match with the order given in the spec (see 3.23), // i.e. check smaller-numbered bits first. // Unroll and UnrollCount loop controls can't be applied simultaneously with // DontUnroll loop control. if (LC & LoopControlUnrollMask) Metadata.push_back(getMetadataFromName("llvm.loop.unroll.enable")); else if (LC & LoopControlDontUnrollMask) Metadata.push_back(getMetadataFromName("llvm.loop.unroll.disable")); if (LC & LoopControlDependencyInfiniteMask) Metadata.push_back(getMetadataFromName("llvm.loop.ivdep.enable")); if (LC & LoopControlDependencyLengthMask) { if (!LoopControlParameters.empty()) { Metadata.push_back(llvm::MDNode::get( *Context, getMetadataFromNameAndParameter("llvm.loop.ivdep.safelen", LoopControlParameters[NumParam]))); ++NumParam; IGC_ASSERT(NumParam <= LoopControlParameters.size() && "Missing loop control parameter!"); } } // Placeholder for LoopControls added in SPIR-V 1.4 spec (see 3.23) if (LC & LoopControlMinIterationsMask) { ++NumParam; IGC_ASSERT(NumParam <= LoopControlParameters.size() && "Missing loop control parameter!"); } if (LC & LoopControlMaxIterationsMask) { ++NumParam; IGC_ASSERT(NumParam <= LoopControlParameters.size() && "Missing loop control parameter!"); } if (LC & LoopControlIterationMultipleMask) { ++NumParam; IGC_ASSERT(NumParam <= LoopControlParameters.size() && "Missing loop control parameter!"); } if (LC & LoopControlPeelCountMask) { ++NumParam; IGC_ASSERT(NumParam <= LoopControlParameters.size() && "Missing loop control parameter!"); } if (LC & LoopControlPartialCountMask && !(LC & LoopControlDontUnrollMask)) { // If unroll factor is set as '1' - disable loop unrolling if (1 == LoopControlParameters[NumParam]) Metadata.push_back(getMetadataFromName("llvm.loop.unroll.disable")); else Metadata.push_back(llvm::MDNode::get( *Context, getMetadataFromNameAndParameter("llvm.loop.unroll.count", LoopControlParameters[NumParam]))); ++NumParam; IGC_ASSERT(NumParam <= LoopControlParameters.size() && "Missing loop control parameter!"); } llvm::MDNode *Node = llvm::MDNode::get(*Context, Metadata); // Set the first operand to refer itself Node->replaceOperandWith(0, Node); BI->setMetadata("llvm.loop", Node); } GlobalValue::LinkageTypes SPIRVToLLVM::transLinkageType(const SPIRVValue* V) { if (V->getLinkageType() == LinkageTypeInternal) { return GlobalValue::InternalLinkage; } else if (V->getLinkageType() == LinkageTypeImport) { // Function declaration if (V->getOpCode() == OpFunction) { if (static_cast(V)->getNumBasicBlock() == 0) return GlobalValue::ExternalLinkage; } // Variable declaration if (V->getOpCode() == OpVariable) { if (static_cast(V)->getInitializer() == 0) return GlobalValue::ExternalLinkage; } // Definition return GlobalValue::AvailableExternallyLinkage; } else {// LinkageTypeExport if (V->getOpCode() == OpVariable) { if (static_cast(V)->getInitializer() == 0 ) // Tentative definition return GlobalValue::CommonLinkage; } return GlobalValue::ExternalLinkage; } } Type * SPIRVToLLVM::transType(SPIRVType *T) { auto Loc = TypeMap.find(T); if (Loc != TypeMap.end()) return Loc->second; T->validate(); switch(T->getOpCode()) { case OpTypeVoid: return mapType(T, Type::getVoidTy(*Context)); case OpTypeBool: return mapType(T, Type::getInt8Ty(*Context)); case OpTypeInt: return mapType(T, Type::getIntNTy(*Context, T->getIntegerBitWidth())); case OpTypeFloat: return mapType(T, transFPType(T)); case OpTypeArray: return mapType(T, ArrayType::get(transType(T->getArrayElementType()), T->getArrayLength())); case OpTypePointer: return mapType(T, PointerType::get(transType(T->getPointerElementType()), SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass()))); case OpTypeVector: return mapType(T, VectorType::get(transType(T->getVectorComponentType()), T->getVectorComponentCount())); case OpTypeOpaque: return mapType(T, StructType::create(*Context, T->getName())); case OpTypeFunction: { auto FT = static_cast(T); auto RT = transType(FT->getReturnType()); std::vector PT; for (size_t I = 0, E = FT->getNumParameters(); I != E; ++I) PT.push_back(transType(FT->getParameterType(I))); return mapType(T, FunctionType::get(RT, PT, false)); } case OpTypeImage:{ return mapType(T, getOrCreateOpaquePtrType(M, transOCLImageTypeName(static_cast(T)))); } case OpTypeSampler: //ulong __builtin_spirv_OpTypeSampler return mapType(T, Type::getInt64Ty(*Context)); case OpTypeSampledImage: case OpTypeVmeImageINTEL: { //ulong3 __builtin_spirv_OpSampledImage return mapType(T, VectorType::get(Type::getInt64Ty(*Context), 3)); } case OpTypeStruct: { auto ST = static_cast(T); auto *pStructTy = StructType::create(*Context, ST->getName()); mapType(ST, pStructTy); SmallVector MT; for (size_t I = 0, E = ST->getMemberCount(); I != E; ++I) MT.push_back(transType(ST->getMemberType(I))); pStructTy->setBody(MT, ST->isPacked()); return pStructTy; } case OpTypePipeStorage: { return mapType(T, Type::getInt8PtrTy(*Context, SPIRAS_Global)); } case OpTypeNamedBarrier: { return mapType(T, getNamedBarrierType()); } default: { auto OC = T->getOpCode(); if (isOpaqueGenericTypeOpCode(OC) || isSubgroupAvcINTELTypeOpCode(OC)) { auto name = isSubgroupAvcINTELTypeOpCode(OC) ? OCLSubgroupINTELTypeOpCodeMap::rmap(OC) : BuiltinOpaqueGenericTypeOpCodeMap::rmap(OC); auto *pST = M->getTypeByName(name); pST = pST ? pST : StructType::create(*Context, name); return mapType(T, PointerType::get(pST, getOCLOpaqueTypeAddrSpace(OC))); } llvm_unreachable("Not implemented"); } } return 0; } std::string SPIRVToLLVM::transTypeToOCLTypeName(SPIRVType *T, bool IsSigned) { switch(T->getOpCode()) { case OpTypeVoid: return "void"; case OpTypeBool: return "bool"; case OpTypeInt: { std::string Prefix = IsSigned ? "" : "u"; switch(T->getIntegerBitWidth()) { case 8: return Prefix + "char"; case 16: return Prefix + "short"; case 32: return Prefix + "int"; case 64: return Prefix + "long"; default: llvm_unreachable("invalid integer size"); return Prefix + std::string("int") + T->getIntegerBitWidth() + "_t"; } } break; case OpTypeFloat: switch(T->getFloatBitWidth()){ case 16: return "half"; case 32: return "float"; case 64: return "double"; default: llvm_unreachable("invalid floating pointer bitwidth"); return std::string("float") + T->getFloatBitWidth() + "_t"; } break; case OpTypeArray: return "array"; case OpTypePointer: { SPIRVType* ET = T->getPointerElementType(); if (isa(ET)) { SPIRVTypeFunction* TF = static_cast(ET); std::string name = transTypeToOCLTypeName(TF->getReturnType()); name += " (*)("; for (unsigned I = 0, E = TF->getNumParameters(); I < E; ++I) name += transTypeToOCLTypeName(TF->getParameterType(I)) + ','; name.back() = ')'; // replace the last comma with a closing brace. return name; } return transTypeToOCLTypeName(ET) + "*"; } case OpTypeVector: return transTypeToOCLTypeName(T->getVectorComponentType()) + T->getVectorComponentCount(); case OpTypeOpaque: return T->getName(); case OpTypeFunction: return "function"; case OpTypeStruct: { auto Name = T->getName(); if (Name.find("struct.") == 0) Name[6] = ' '; else if (Name.find("union.") == 0) Name[5] = ' '; return Name; } case OpTypePipe: return "pipe"; case OpTypeSampler: return "sampler_t"; case OpTypeImage: return rmap(static_cast(T)->getDescriptor()); default: if (isOpaqueGenericTypeOpCode(T->getOpCode())) { auto Name = BuiltinOpaqueGenericTypeOpCodeMap::rmap(T->getOpCode()); if (Name.find("opencl.") == 0) { return Name.substr(7); } else { return Name; } } llvm_unreachable("Not implemented"); return "unknown"; } } std::vector SPIRVToLLVM::transTypeVector(const std::vector &BT) { std::vector T; for (auto I: BT) T.push_back(transType(I)); return T; } std::vector SPIRVToLLVM::transValue(const std::vector &BV, Function *F, BasicBlock *BB, BoolAction Action) { std::vector V; for (auto I: BV) V.push_back(transValue(I, F, BB, true, Action)); return V; } bool SPIRVToLLVM::isSPIRVCmpInstTransToLLVMInst(SPIRVInstruction* BI) const { auto OC = BI->getOpCode(); return isCmpOpCode(OC) && !(OC >= OpLessOrGreater && OC <= OpUnordered); } Value * SPIRVToLLVM::transValue(SPIRVValue *BV, Function *F, BasicBlock *BB, bool CreatePlaceHolder, BoolAction Action) { auto procBool = [&](Value *v) { if (Action == BoolAction::Noop) return v; if (!BV->hasType()) return v; if (!BV->getType()->isTypeVectorOrScalarBool()) return v; return Action == BoolAction::Promote ? promoteBool(v, BB) : truncBool(v, BB); }; SPIRVToLLVMValueMap::iterator Loc = ValueMap.find(BV); if (Loc != ValueMap.end() && (!PlaceholderMap.count(BV) || CreatePlaceHolder)) { return procBool(Loc->second); } BV->validate(); auto V = transValueWithoutDecoration(BV, F, BB, CreatePlaceHolder); if (!V) { return nullptr; } V->setName(BV->getName()); if (!transDecoration(BV, V)) { IGC_ASSERT_EXIT(0 && "trans decoration fail"); return nullptr; } return procBool(V); } Value * SPIRVToLLVM::transConvertInst(SPIRVValue* BV, Function* F, BasicBlock* BB) { SPIRVUnary* BC = static_cast(BV); auto Src = transValue(BC->getOperand(0), F, BB, BB ? true : false); auto Dst = transType(BC->getType()); CastInst::CastOps CO = Instruction::BitCast; bool IsExt = Dst->getScalarSizeInBits() > Src->getType()->getScalarSizeInBits(); switch (BC->getOpCode()) { case OpPtrCastToGeneric: case OpGenericCastToPtr: CO = Instruction::AddrSpaceCast; break; case OpSConvert: CO = IsExt ? Instruction::SExt : Instruction::Trunc; break; case OpUConvert: CO = IsExt ? Instruction::ZExt : Instruction::Trunc; break; case OpFConvert: CO = IsExt ? Instruction::FPExt : Instruction::FPTrunc; break; default: CO = static_cast(OpCodeMap::rmap(BC->getOpCode())); } IGC_ASSERT(CastInst::isCast(CO) && "Invalid cast op code"); if (BB) return CastInst::Create(CO, Src, Dst, BV->getName(), BB); return ConstantExpr::getCast(CO, dyn_cast(Src), Dst); } BinaryOperator *SPIRVToLLVM::transShiftLogicalBitwiseInst(SPIRVValue* BV, BasicBlock* BB,Function* F) { SPIRVBinary* BBN = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); Instruction::BinaryOps BO; auto OP = BBN->getOpCode(); if (isLogicalOpCode(OP)) OP = IntBoolOpMap::rmap(OP); BO = static_cast(OpCodeMap::rmap(OP)); auto Inst = BinaryOperator::Create(BO, transValue(BBN->getOperand(0), F, BB), transValue(BBN->getOperand(1), F, BB), BV->getName(), BB); if (BV->hasDecorate(DecorationNoSignedWrap)) { Inst->setHasNoSignedWrap(true); } if (BV->hasDecorate(DecorationNoUnsignedWrap)) { Inst->setHasNoUnsignedWrap(true); } return Inst; } Instruction * SPIRVToLLVM::transLifetimeInst(SPIRVInstTemplateBase* BI, BasicBlock* BB, Function* F) { auto ID = (BI->getOpCode() == OpLifetimeStart) ? Intrinsic::lifetime_start : Intrinsic::lifetime_end; #if LLVM_VERSION_MAJOR >= 7 auto *pFunc = Intrinsic::getDeclaration(M, ID, llvm::ArrayRef(PointerType::getInt8PtrTy(*Context))); #else auto *pFunc = Intrinsic::getDeclaration(M, ID); #endif auto *pPtr = transValue(BI->getOperand(0), F, BB); Value *pArgs[] = { ConstantInt::get(Type::getInt64Ty(*Context), BI->getOpWord(1)), CastInst::CreatePointerCast(pPtr, PointerType::getInt8PtrTy(*Context), "", BB) }; auto *pCI = CallInst::Create(pFunc, pArgs, "", BB); return pCI; } Instruction * SPIRVToLLVM::transCmpInst(SPIRVValue* BV, BasicBlock* BB, Function* F) { SPIRVCompare* BC = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); SPIRVType* BT = BC->getOperand(0)->getType(); Instruction* Inst = nullptr; if (BT->isTypeVectorOrScalarInt() || BT->isTypePointer() || BT->isTypeQueue() || BT->isTypeBool()) Inst = new ICmpInst(*BB, CmpMap::rmap(BC->getOpCode()), transValue(BC->getOperand(0), F, BB), transValue(BC->getOperand(1), F, BB)); else if (BT->isTypeVectorOrScalarFloat()) Inst = new FCmpInst(*BB, CmpMap::rmap(BC->getOpCode()), transValue(BC->getOperand(0), F, BB), transValue(BC->getOperand(1), F, BB)); IGC_ASSERT(Inst && "not implemented"); return Inst; } bool SPIRVToLLVM::postProcessOCL() { // I think we dont need it std::vector structFuncs; for (auto& F : M->functions()) { if (F.getReturnType()->isStructTy()) { structFuncs.push_back(&F); } } for (auto structFunc : structFuncs) postProcessFunctionsReturnStruct(structFunc); std::vector aggrFuncs; for (auto& F : M->functions()) { if (std::any_of(F.arg_begin(), F.arg_end(), [](Argument& arg) { return arg.getType()->isAggregateType(); }) ) { aggrFuncs.push_back(&F); } } for (auto aggrFunc : aggrFuncs) postProcessFunctionsWithAggregateArguments(aggrFunc); return true; } bool SPIRVToLLVM::postProcessFunctionsReturnStruct(Function *F) { if (!F->getReturnType()->isStructTy()) return false; std::string Name = F->getName(); F->setName(Name + ".old"); std::vector ArgTys; getFunctionTypeParameterTypes(F->getFunctionType(), ArgTys); ArgTys.insert(ArgTys.begin(), PointerType::get(F->getReturnType(), SPIRAS_Private)); auto newFType = FunctionType::get(Type::getVoidTy(*Context), ArgTys, false); auto NewF = cast(M->getOrInsertFunction(Name, newFType)); NewF->setCallingConv(F->getCallingConv()); if (!F->isDeclaration()) { ValueToValueMapTy VMap; llvm::SmallVector Returns; auto OldArgIt = F->arg_begin(); auto NewArgIt = NewF->arg_begin(); ++NewArgIt; // Skip first argument that we added. for (; OldArgIt != F->arg_end(); ++OldArgIt, ++NewArgIt) { NewArgIt->setName(OldArgIt->getName()); VMap[&*OldArgIt] = &*NewArgIt; } CloneFunctionInto(NewF, F, VMap, true, Returns); auto DL = M->getDataLayout(); const auto ptrSize = DL.getPointerSize(); for (auto RetInst : Returns) { IGCLLVM::IRBuilder<> builder(RetInst); Type* retTy = RetInst->getReturnValue()->getType(); Value* returnedValPtr = builder.CreateAlloca(retTy); builder.CreateStore(RetInst->getReturnValue(), returnedValPtr); auto size = DL.getTypeAllocSize(retTy); builder.CreateMemCpy(&*NewF->arg_begin(), returnedValPtr, size, ptrSize); builder.CreateRetVoid(); RetInst->eraseFromParent(); } } for (auto I = F->user_begin(), E = F->user_end(); I != E;) { if (auto CI = dyn_cast(*I++)) { auto Args = getArguments(CI); IGCLLVM::IRBuilder<> builder(CI); //auto Alloca = new AllocaInst(CI->getType(), "", CI); auto Alloca = builder.CreateAlloca(CI->getType()); Args.insert(Args.begin(), Alloca); auto NewCI = CallInst::Create(NewF, Args, "", CI); NewCI->setCallingConv(CI->getCallingConv()); auto Load = new LoadInst(Alloca,"",CI); CI->replaceAllUsesWith(Load); CI->eraseFromParent(); } } F->dropAllReferences(); F->removeFromParent(); return true; } bool SPIRVToLLVM::postProcessFunctionsWithAggregateArguments(Function* F) { auto Name = F->getName(); auto Attrs = F->getAttributes(); auto DL = M->getDataLayout(); auto ptrSize = DL.getPointerSize(); mutateFunction (F, [=](CallInst *CI, std::vector &Args) { auto FBegin = CI->getParent()->getParent()->begin()->getFirstInsertionPt(); IGCLLVM::IRBuilder<> builder(&(*FBegin)); for (auto &I:Args) { auto T = I->getType(); if (!T->isAggregateType()) continue; if (auto constVal = dyn_cast(I)) { I = new GlobalVariable(*M, T, true, GlobalValue::InternalLinkage, constVal); } else { builder.SetInsertPoint(CI); Value* allocaInst = builder.CreateAlloca(T); builder.CreateStore(I, allocaInst); I = allocaInst; } builder.SetInsertPoint(&*FBegin); auto Alloca = builder.CreateAlloca(T); Alloca->setAlignment(MaybeAlign(ptrSize)); auto size = DL.getTypeAllocSize(T); builder.SetInsertPoint(CI); builder.CreateMemCpy(Alloca, I, size, ptrSize); if (T->isArrayTy()) { I = ptrSize > 4 ? builder.CreateConstInBoundsGEP2_64(Alloca, 0, 0) : builder.CreateConstInBoundsGEP2_32(nullptr, Alloca, 0, 0); } else if (T->isStructTy()) { I = Alloca; } else { llvm_unreachable("Unknown aggregate type!"); } } return Name; }, false, &Attrs); return true; } std::string SPIRVToLLVM::transOCLPipeTypeAccessQualifier(spv::SPIRVTypePipe* ST) { return SPIRSPIRVAccessQualifierMap::rmap(ST->getAccessQualifier()); } Value * SPIRVToLLVM::oclTransConstantSampler(spv::SPIRVConstantSampler* BCS) { auto Lit = (BCS->getAddrMode() << 1) | BCS->getNormalized() | ((BCS->getFilterMode() + 1) << 4); auto Ty = IntegerType::getInt64Ty(*Context); return ConstantInt::get(Ty, Lit); } Value *SPIRVToLLVM::promoteBool(Value *pVal, BasicBlock *BB) { if (!pVal->getType()->getScalarType()->isIntegerTy(1)) return pVal; auto *PromoType = isa(pVal->getType()) ? cast(VectorType::get(Type::getInt8Ty(pVal->getContext()), pVal->getType()->getVectorNumElements())) : Type::getInt8Ty(pVal->getContext()); if (auto *C = dyn_cast(pVal)) return ConstantExpr::getZExtOrBitCast(C, PromoType); if (BB == nullptr) return pVal; if (auto *Arg = dyn_cast(pVal)) { auto &entry = BB->getParent()->getEntryBlock(); Instruction *Cast = nullptr; if (entry.empty()) { Cast = CastInst::CreateZExtOrBitCast(Arg, PromoType, "i1promo", BB); } else { auto IP = entry.begin(); while (isa(IP)) ++IP; if (IP == BB->end()) Cast = CastInst::CreateZExtOrBitCast(Arg, PromoType, "i1promo", BB); else Cast = CastInst::CreateZExtOrBitCast(Arg, PromoType, "i1promo", &(*IP)); } return Cast; } auto *pInst = cast(pVal); auto *Cast = CastInst::CreateZExtOrBitCast(pInst, PromoType, "i1promo"); Cast->insertAfter(pInst); return Cast; } Value *SPIRVToLLVM::truncBool(Value *pVal, BasicBlock *BB) { if (!pVal->getType()->getScalarType()->isIntegerTy(8)) return pVal; auto *TruncType = isa(pVal->getType()) ? cast(VectorType::get(Type::getInt1Ty(pVal->getContext()), pVal->getType()->getVectorNumElements())) : Type::getInt1Ty(pVal->getContext()); if (auto *C = dyn_cast(pVal)) return ConstantExpr::getTruncOrBitCast(C, TruncType); if (BB == nullptr) return pVal; if (auto *Arg = dyn_cast(pVal)) { auto &entry = BB->getParent()->getEntryBlock(); Instruction *Cast = nullptr; if (entry.empty()) { Cast = CastInst::CreateTruncOrBitCast(Arg, TruncType, "i1trunc", BB); } else { auto IP = entry.begin(); while (isa(IP)) ++IP; if (IP == BB->end()) Cast = CastInst::CreateTruncOrBitCast(Arg, TruncType, "i1trunc", BB); else Cast = CastInst::CreateTruncOrBitCast(Arg, TruncType, "i1trunc", &(*IP)); } return Cast; } auto *pInst = cast(pVal); auto *Cast = CastInst::CreateTruncOrBitCast(pInst, TruncType, "i1trunc"); Cast->insertAfter(pInst); return Cast; } Type *SPIRVToLLVM::truncBoolType(SPIRVType *SPVType, Type *LLType) { if (!SPVType->isTypeVectorOrScalarBool()) return LLType; return isa(LLType) ? cast(VectorType::get(Type::getInt1Ty(LLType->getContext()), LLType->getVectorNumElements())) : Type::getInt1Ty(LLType->getContext()); } /// For instructions, this function assumes they are created in order /// and appended to the given basic block. An instruction may use a /// instruction from another BB which has not been translated. Such /// instructions should be translated to place holders at the point /// of first use, then replaced by real instructions when they are /// created. /// /// When CreatePlaceHolder is true, create a load instruction of a /// global variable as placeholder for SPIRV instruction. Otherwise, /// create instruction and replace placeholder if there is one. Value * SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, BasicBlock *BB, bool CreatePlaceHolder){ auto OC = BV->getOpCode(); IntBoolOpMap::rfind(OC, &OC); // Translation of non-instruction values switch(OC) { case OpSpecConstant: case OpConstant: { SPIRVConstant *BConst = static_cast(BV); SPIRVType *BT = BV->getType(); Type *LT = transType(BT); uint64_t V = BConst->getZExtIntValue(); if(BV->hasDecorate(DecorationSpecId)) { IGC_ASSERT_EXIT(OC == OpSpecConstant && "Only SpecConstants can be specialized!"); SPIRVWord specid = *BV->getDecorate(DecorationSpecId).begin(); if(BM->isSpecConstantSpecialized(specid)) V = BM->getSpecConstant(specid); } switch(BT->getOpCode()) { case OpTypeBool: case OpTypeInt: return mapValue(BV, ConstantInt::get(LT, V, static_cast(BT)->isSigned())); case OpTypeFloat: { const llvm::fltSemantics *FS = nullptr; switch (BT->getFloatBitWidth()) { case 16: FS = &APFloat::IEEEhalf(); break; case 32: FS = &APFloat::IEEEsingle(); break; case 64: FS = &APFloat::IEEEdouble(); break; default: IGC_ASSERT_EXIT(0 && "invalid float type"); break; } return mapValue(BV, ConstantFP::get(*Context, APFloat(*FS, APInt(BT->getFloatBitWidth(), V)))); } default: llvm_unreachable("Not implemented"); return NULL; } } break; case OpSpecConstantTrue: if (BV->hasDecorate(DecorationSpecId)) { SPIRVWord specid = *BV->getDecorate(DecorationSpecId).begin(); if(BM->getSpecConstant(specid)) return mapValue(BV, ConstantInt::getTrue(*Context)); else return mapValue(BV, ConstantInt::getFalse(*Context)); } // intentional fall-through: if decoration was not specified, treat this // as a OpConstantTrue (default spec constant value) case OpConstantTrue: return mapValue(BV, ConstantInt::getTrue(*Context)); case OpSpecConstantFalse: if (BV->hasDecorate(DecorationSpecId)) { SPIRVWord specid = *BV->getDecorate(DecorationSpecId).begin(); if (BM->getSpecConstant(specid)) return mapValue(BV, ConstantInt::getTrue(*Context)); else return mapValue(BV, ConstantInt::getFalse(*Context)); } // intentional fall-through: if decoration was not specified, treat this // as a OpConstantFalse (default spec constant value) case OpConstantFalse: return mapValue(BV, ConstantInt::getFalse(*Context)); case OpConstantNull: { auto LT = transType(BV->getType()); return mapValue(BV, Constant::getNullValue(LT)); } case OpSpecConstantComposite: case OpConstantComposite: { auto BCC = static_cast(BV); std::vector CV; for (auto &I:BCC->getElements()) CV.push_back(dyn_cast(transValue(I, F, BB))); switch(BV->getType()->getOpCode()) { case OpTypeVector: return mapValue(BV, ConstantVector::get(CV)); case OpTypeArray: return mapValue(BV, ConstantArray::get( dyn_cast(transType(BCC->getType())), CV)); case OpTypeStruct: return mapValue(BV, ConstantStruct::get( dyn_cast(transType(BCC->getType())), CV)); default: llvm_unreachable("not implemented"); return nullptr; } } break; case OpCompositeConstruct: { auto BCC = static_cast(BV); std::vector CV; for(auto &I : BCC->getElements()) { CV.push_back( transValue( I,F,BB ) ); } switch(BV->getType()->getOpCode()) { case OpTypeVector: { Type *T = transType( BCC->getType() ); Value *undef = llvm::UndefValue::get( T ); Value *elm1 = undef; uint32_t pos = 0; auto CreateCompositeConstruct = [&]( Value* Vec,Value* ValueToBeInserted,uint32_t Pos ) { Value *elm = InsertElementInst::Create( Vec, ValueToBeInserted, ConstantInt::get( *Context,APInt( 32,Pos ) ), BCC->getName(),BB ); return elm; }; for(unsigned i = 0; i < CV.size(); i++) { if(CV[i]->getType()->isVectorTy()) { for(uint32_t j = 0; j < CV[i]->getType()->getVectorNumElements(); j++) { Value *v = ExtractElementInst::Create( CV[i],ConstantInt::get( *Context,APInt( 32,j ) ),BCC->getName(),BB ); elm1 = CreateCompositeConstruct( elm1,v,pos++ ); } } else { elm1 = CreateCompositeConstruct( elm1,CV[i],pos++ ); } } return mapValue( BV,elm1 ); } break; case OpTypeArray: case OpTypeStruct: { Type *T = transType( BV->getType() ); Value *undef = llvm::UndefValue::get( T ); Value *elm1 = undef; for(unsigned i = 0; i < CV.size(); i++) { elm1 = InsertValueInst::Create( elm1, CV[i], i, BCC->getName(),BB ); } return mapValue( BV,elm1 ); } break; default: llvm_unreachable( "not implemented" ); return nullptr; } } break; case OpConstantSampler: { auto BCS = static_cast(BV); return mapValue(BV, oclTransConstantSampler(BCS)); } case OpSpecConstantOp: { auto BI = createInstFromSpecConstantOp( static_cast(BV)); return mapValue(BV, transValue(BI, nullptr, nullptr, false)); } case OpConstantPipeStorage: { auto CPS = static_cast(BV); const uint32_t packetSize = CPS->GetPacketSize(); const uint32_t packetAlign = CPS->GetPacketAlignment(); const uint32_t maxNumPackets = CPS->GetCapacity(); // This value matches the definition from the runtime and that from pipe.cl. const uint32_t INTEL_PIPE_HEADER_RESERVED_SPACE = 128; const uint32_t numPacketsAlloc = maxNumPackets + 1; const uint32_t bufSize = packetSize * numPacketsAlloc + INTEL_PIPE_HEADER_RESERVED_SPACE; SmallVector buf(bufSize, 0); // Initialize the pipe_max_packets field in the control structure. for (unsigned i = 0; i < 4; i++) buf[i] = (uint8_t)((numPacketsAlloc >> (8 * i)) & 0xff); auto *pInit = ConstantDataArray::get(*Context, buf); GlobalVariable *pGV = new GlobalVariable( *M, pInit->getType(), false, GlobalVariable::InternalLinkage, pInit, Twine("pipebuf"), nullptr, GlobalVariable::ThreadLocalMode::NotThreadLocal, SPIRAS_Global); pGV->setAlignment(MaybeAlign(std::max(4U, packetAlign))); auto *pStorageTy = transType(CPS->getType()); return mapValue(CPS, ConstantExpr::getBitCast(pGV, pStorageTy)); } case OpUndef: return mapValue(BV, UndefValue::get(transType(BV->getType()))); case OpVariable: { auto BVar = static_cast(BV); auto Ty = transType(BVar->getType()->getPointerElementType()); bool IsConst = BVar->isConstant(); llvm::GlobalValue::LinkageTypes LinkageTy = transLinkageType(BVar); Constant *Initializer = nullptr; SPIRVStorageClassKind BS = BVar->getStorageClass(); SPIRVValue *Init = BVar->getInitializer(); if (Init) Initializer = dyn_cast(transValue(Init, F, BB, false)); else if (LinkageTy == GlobalValue::CommonLinkage) // In LLVM variables with common linkage type must be initilized by 0 Initializer = Constant::getNullValue(Ty); else if (BS == StorageClassWorkgroupLocal) Initializer = UndefValue::get(Ty); if (BS == StorageClassFunction && !Init) { IGC_ASSERT(BB && "Invalid BB"); IGCLLVM::IRBuilder<> builder(BB); //return mapValue(BV, new AllocaInst(Ty, BV->getName(), BB)); return mapValue(BV, builder.CreateAlloca(Ty, nullptr, BV->getName())); } auto AddrSpace = SPIRSPIRVAddrSpaceMap::rmap(BS); auto LVar = new GlobalVariable(*M, Ty, IsConst, LinkageTy, Initializer, BV->getName(), 0, GlobalVariable::NotThreadLocal, AddrSpace); GlobalVariable::UnnamedAddr addrType = (IsConst && Ty->isArrayTy() && Ty->getArrayElementType()->isIntegerTy(8)) ? GlobalVariable::UnnamedAddr::Global : GlobalVariable::UnnamedAddr::None; LVar->setUnnamedAddr(addrType); SPIRVBuiltinVariableKind BVKind = BuiltInCount; if (BVar->isBuiltin(&BVKind)) BuiltinGVMap[LVar] = BVKind; return mapValue(BV, LVar); } break; case OpFunctionParameter: { auto BA = static_cast(BV); IGC_ASSERT(F && "Invalid function"); unsigned ArgNo = 0; for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I, ++ArgNo) { if (ArgNo == BA->getArgNo()) return mapValue(BV, &(*I)); } IGC_ASSERT_EXIT(0 && "Invalid argument"); return NULL; } break; case OpFunction: return mapValue(BV, transFunction(static_cast(BV))); case OpAsmINTEL: return mapValue(BV, transAsmINTEL(static_cast(BV), F, BB)); case OpLabel: return mapValue(BV, BasicBlock::Create(*Context, BV->getName(), F)); break; default: // do nothing break; } // During translation of OpSpecConstantOp we create an instruction // corresponding to the Opcode operand and then translate this instruction. // For such instruction BB and F should be nullptr, because it is a constant // expression declared out of scope of any basic block or function. // All other values require valid BB pointer. IGC_ASSERT(((isSpecConstantOpAllowedOp(OC) && !F && !BB) || BB) && "Invalid BB"); // Creation of place holder if (CreatePlaceHolder) { auto GV = new GlobalVariable(*M, transType(BV->getType()), false, GlobalValue::PrivateLinkage, nullptr, std::string(kPlaceholderPrefix) + BV->getName(), 0, GlobalVariable::NotThreadLocal, 0); auto LD = new LoadInst(GV, BV->getName(), BB); PlaceholderMap[BV] = LD; return mapValue(BV, LD); } // Translation of instructions switch (BV->getOpCode()) { case OpBranch: { auto BR = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); auto BI = BranchInst::Create( dyn_cast(transValue(BR->getTargetLabel(), F, BB)), BB); SPIRVInstruction *Prev = BR->getPrevious(); if(Prev && Prev->getOpCode() == OpLoopMerge) if (auto LM = static_cast(Prev)) setLLVMLoopMetadata(LM, BI); return mapValue(BV, BI); } break; case OpBranchConditional: { auto BR = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); auto BC = BranchInst::Create( dyn_cast(transValue(BR->getTrueLabel(), F, BB)), dyn_cast(transValue(BR->getFalseLabel(), F, BB)), // cond must be an i1, truncate bool to i1 if it was an i8. transValue(BR->getCondition(), F, BB, true, BoolAction::Truncate), BB); SPIRVInstruction *Prev = BR->getPrevious(); if (Prev && Prev->getOpCode() == OpLoopMerge) if (auto LM = static_cast(Prev)) setLLVMLoopMetadata(LM, BC); return mapValue(BV, BC); } break; case OpPhi: { auto Phi = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); auto LPhi = dyn_cast(mapValue(BV, PHINode::Create( transType(Phi->getType()), Phi->getPairs().size() / 2, Phi->getName(), BB))); Phi->foreachPair([&](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB, size_t Index){ auto Translated = transValue(IncomingV, F, BB); LPhi->addIncoming(Translated, dyn_cast(transValue(IncomingBB, F, BB))); }); return LPhi; } break; case OpReturn: IGC_ASSERT(BB && "Invalid BB"); return mapValue(BV, ReturnInst::Create(*Context, BB)); break; case OpReturnValue: { auto RV = static_cast(BV); return mapValue(BV, ReturnInst::Create(*Context, transValue(RV->getReturnValue(), F, BB), BB)); } break; case OpStore: { SPIRVStore *BS = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); auto *pValue = transValue(BS->getSrc(), F, BB); auto *pPointer = transValue(BS->getDst(), F, BB); bool isVolatile = BS->hasDecorate(DecorationVolatile) || BS->SPIRVMemoryAccess::getVolatile() != 0; unsigned alignment = BS->SPIRVMemoryAccess::getAlignment(); if (auto *CS = dyn_cast(pValue)) { // Break up a store with a literal struct as the value as we don't have any // legalization infrastructure to do it: // Ex. // store %0 { <2 x i32> , %1 { i32 -2100483600, i8 -128 } }, %0 addrspace(1)* %a // => // %CS.tmpstore = alloca %0 // %0 = getelementptr inbounds %0* %CS.tmpstore, i32 0, i32 0 // store <2 x i32> , <2 x i32>* %0 // %1 = getelementptr inbounds %0* %CS.tmpstore, i32 0, i32 1 // %2 = getelementptr inbounds %1* %1, i32 0, i32 0 // store i32 -2100483600, i32* %2 // %3 = getelementptr inbounds %1* %1, i32 0, i32 1 // store i8 -128, i8* %3 // %4 = bitcast %0 addrspace(1)* %a to i8 addrspace(1)* // %5 = bitcast %0* %CS.tmpstore to i8* // call void @llvm.memcpy.p1i8.p0i8.i64(i8 addrspace(1)* %4, i8* %5, i64 16, i32 0, i1 false) // So we emit this store in a similar fashion as clang would. IGCLLVM::IRBuilder<> IRB(&F->getEntryBlock(), F->getEntryBlock().begin()); auto DL = M->getDataLayout(); std::function LowerConstantStructStore = [&](ConstantStruct *CS, Value *pointer) { for (unsigned I = 0, E = CS->getNumOperands(); I != E; I++) { auto *op = CS->getOperand(I); auto *pGEP = IRB.CreateConstInBoundsGEP2_32(nullptr, pointer, 0, I); if (auto *InnerCS = dyn_cast(op)) LowerConstantStructStore(InnerCS, pGEP); else IRB.CreateStore(op, pGEP); } }; auto *pAlloca = IRB.CreateAlloca(pValue->getType(), nullptr, "CS.tmpstore"); IRB.SetInsertPoint(BB); LowerConstantStructStore(CS, pAlloca); auto *pDst = IRB.CreateBitCast(pPointer, Type::getInt8PtrTy(*Context, pPointer->getType()->getPointerAddressSpace())); auto *pSrc = IRB.CreateBitCast(pAlloca, Type::getInt8PtrTy(*Context)); auto *pMemCpy = IRB.CreateMemCpy(pDst, pSrc, DL.getTypeAllocSize(pAlloca->getAllocatedType()), alignment, isVolatile); return mapValue(BV, pMemCpy); } return mapValue(BV, new StoreInst( pValue, pPointer, isVolatile, MaybeAlign(alignment), BB)); } break; case OpLoad: { SPIRVLoad *BL = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); return mapValue(BV, new LoadInst( transValue(BL->getSrc(), F, BB), BV->getName(), BL->hasDecorate(DecorationVolatile) || BL->SPIRVMemoryAccess::getVolatile() != 0, MaybeAlign(BL->SPIRVMemoryAccess::getAlignment()), BB)); } break; case OpCopyMemorySized: { SPIRVCopyMemorySized *BC = static_cast(BV); CallInst *CI = nullptr; llvm::Value *Dst = transValue(BC->getTarget(), F, BB); unsigned Align = BC->getAlignment(); llvm::Value *Size = transValue(BC->getSize(), F, BB); bool IsVolatile = BC->SPIRVMemoryAccess::getVolatile(); IGCLLVM::IRBuilder<> Builder(BB); // If we copy from zero-initialized array, we can optimize it to llvm.memset if (BC->getSource()->getOpCode() == OpBitcast) { SPIRVValue *Source = static_cast(BC->getSource())->getOperand(0); if (Source->isVariable()) { auto *Init = static_cast(Source)->getInitializer(); if (Init && Init->getOpCode() == OpConstantNull) { SPIRVType *Ty = static_cast(Init)->getType(); if (Ty->isTypeArray()) { Type* Int8Ty = Type::getInt8Ty(Dst->getContext()); llvm::Value* Src = ConstantInt::get(Int8Ty, 0); llvm::Value* newDst = Dst; if (!Dst->getType()->getPointerElementType()->isIntegerTy(8)) { Type* Int8PointerTy = Type::getInt8PtrTy(Dst->getContext(), Dst->getType()->getPointerAddressSpace()); newDst = llvm::BitCastInst::CreatePointerCast(Dst, Int8PointerTy, "", BB); } CI = Builder.CreateMemSet(newDst, Src, Size, MaybeAlign(Align), IsVolatile); } } } } if (!CI) { llvm::Value *Src = transValue(BC->getSource(), F, BB); CI = Builder.CreateMemCpy(Dst, Src, Size, Align, IsVolatile); } if (isFuncNoUnwind()) CI->getFunction()->addFnAttr(Attribute::NoUnwind); return mapValue(BV, CI); } break; case OpCopyObject: { auto BI = static_cast(BV); auto source = transValue( BI->getOperand( 0 ),F,BB ); return mapValue( BV,source ); } case OpSelect: { SPIRVSelect *BS = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); return mapValue(BV, SelectInst::Create( // cond must be an i1, truncate bool to i1 if it was an i8. transValue(BS->getCondition(), F, BB, true, BoolAction::Truncate), transValue(BS->getTrueValue(), F, BB), transValue(BS->getFalseValue(), F, BB), BV->getName(), BB)); } break; // OpenCL Compiler does not use this instruction // Should be translated at OpBranch or OpBranchConditional cases case OpLoopMerge: { return nullptr; } break; case OpSwitch: { auto BS = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); auto Select = transValue(BS->getSelect(), F, BB); auto LS = SwitchInst::Create(Select, dyn_cast(transValue(BS->getDefault(), F, BB)), BS->getNumPairs(), BB); BS->foreachPair( [&](SPIRVSwitch::LiteralTy Literals, SPIRVBasicBlock *Label) { IGC_ASSERT(!Literals.empty() && "Literals should not be empty"); IGC_ASSERT(Literals.size() <= 2 && "Number of literals should not be more then two"); uint64_t Literal = uint64_t(Literals.at(0)); if (Literals.size() == 2) { Literal += uint64_t(Literals.at(1)) << 32; } LS->addCase(ConstantInt::get(dyn_cast(Select->getType()), Literal), dyn_cast(transValue(Label, F, BB))); }); return mapValue(BV, LS); } break; case OpAccessChain: case OpInBoundsAccessChain: case OpPtrAccessChain: case OpInBoundsPtrAccessChain: { auto AC = static_cast(BV); auto Base = transValue(AC->getBase(), F, BB); auto Index = transValue(AC->getIndices(), F, BB); if (!AC->hasPtrIndex()) Index.insert(Index.begin(), getInt32(M, 0)); auto IsInbound = AC->isInBounds(); Value *V = nullptr; if (BB) { auto GEP = GetElementPtrInst::Create(nullptr, Base, Index, BV->getName(), BB); GEP->setIsInBounds(IsInbound); V = GEP; } else { V = ConstantExpr::getGetElementPtr(nullptr, dyn_cast(Base), Index, IsInbound); } return mapValue(BV, V); } break; case OpCompositeExtract: { SPIRVCompositeExtract *CE = static_cast(BV); auto Type = CE->getComposite()->getType(); IGC_ASSERT(BB && "Invalid BB"); IGC_ASSERT(CE->getIndices().size() == 1 && "Invalid index"); if (Type->isTypeVector()) { return mapValue(BV, ExtractElementInst::Create( transValue(CE->getComposite(), F, BB), ConstantInt::get(*Context, APInt(32, CE->getIndices()[0])), BV->getName(), BB)); } else { return mapValue(BV, ExtractValueInst::Create( transValue(CE->getComposite(), F, BB), CE->getIndices(), BV->getName(), BB)); } } break; case OpVectorExtractDynamic: { auto CE = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); return mapValue(BV, ExtractElementInst::Create( transValue(CE->getVector(), F, BB), transValue(CE->getIndex(), F, BB), BV->getName(), BB)); } break; case OpCompositeInsert: { auto CI = static_cast(BV); auto Type = CI->getComposite()->getType(); IGC_ASSERT(BB && "Invalid BB"); IGC_ASSERT(CI->getIndices().size() == 1 && "Invalid index"); if (Type->isTypeVector()) { return mapValue(BV, InsertElementInst::Create( transValue(CI->getComposite(), F, BB), transValue(CI->getObject(), F, BB), ConstantInt::get(*Context, APInt(32, CI->getIndices()[0])), BV->getName(), BB)); } else { return mapValue(BV, InsertValueInst::Create( transValue(CI->getComposite(), F, BB), transValue(CI->getObject(), F, BB), CI->getIndices(), BV->getName(), BB)); } } break; case OpVectorInsertDynamic: { auto CI = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); return mapValue(BV, InsertElementInst::Create( transValue(CI->getVector(), F, BB), transValue(CI->getComponent(), F, BB), transValue(CI->getIndex(), F, BB), BV->getName(), BB)); } break; case OpVectorShuffle: { auto VS = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); std::vector Components; IntegerType *Int32Ty = IntegerType::get(*Context, 32); for (auto I : VS->getComponents()) { if (I == static_cast(-1)) Components.push_back(UndefValue::get(Int32Ty)); else Components.push_back(ConstantInt::get(Int32Ty, I)); } return mapValue(BV, new ShuffleVectorInst( transValue(VS->getVector1(), F, BB), transValue(VS->getVector2(), F, BB), ConstantVector::get(Components), BV->getName(), BB)); } break; case OpFunctionCall: { SPIRVFunctionCall *BC = static_cast(BV); IGC_ASSERT(BB && "Invalid BB"); auto Call = CallInst::Create( transFunction(BC->getFunction()), transValue(BC->getArgumentValues(), F, BB), BC->getName(), BB); setCallingConv(Call); setAttrByCalledFunc(Call); return mapValue(BV, Call); } break; case OpAsmCallINTEL: return mapValue( BV, transAsmCallINTEL(static_cast(BV), F, BB)); case OpFunctionPointerCallINTEL: { SPIRVFunctionPointerCallINTEL *BC = static_cast(BV); auto Call = CallInst::Create(transValue(BC->getCalledValue(), F, BB), transValue(BC->getArgumentValues(), F, BB), BC->getName(), BB); // Assuming we are calling a regular device function Call->setCallingConv(CallingConv::SPIR_FUNC); // Don't set attributes, because at translation time we don't know which // function exactly we are calling. return mapValue(BV, Call); } case OpFunctionPointerINTEL: { SPIRVFunctionPointerINTEL *BC = static_cast(BV); SPIRVFunction* F = BC->getFunction(); BV->setName(F->getName()); return mapValue(BV, transFunction(F)); } case OpExtInst: return mapValue(BV, transOCLBuiltinFromExtInst( static_cast(BV), BB)); break; case OpSNegate: { SPIRVUnary *BC = static_cast(BV); return mapValue(BV, BinaryOperator::CreateNSWNeg( transValue(BC->getOperand(0), F, BB), BV->getName(), BB)); } case OpFNegate: { SPIRVUnary *BC = static_cast(BV); return mapValue(BV, BinaryOperator::CreateFNeg( transValue(BC->getOperand(0), F, BB), BV->getName(), BB)); } break; case OpNot: { SPIRVUnary *BC = static_cast(BV); return mapValue(BV, BinaryOperator::CreateNot( transValue(BC->getOperand(0), F, BB), BV->getName(), BB)); } break; case OpSizeOf: { auto BI = static_cast(BV); IGC_ASSERT(BI->getOpWords().size() == 1 && "OpSizeOf takes one argument!"); // getOperands() returns SPIRVValue(s) but this argument is a SPIRVType so // we have to just grab it by its entry id. auto pArg = BI->get(BI->getOpWord(0)); auto pointee = pArg->getPointerElementType(); auto DL = M->getDataLayout(); uint64_t size = DL.getTypeAllocSize(transType(pointee)); return mapValue(BV, ConstantInt::get(Type::getInt32Ty(*Context), size)); } case OpCreatePipeFromPipeStorage: { auto BI = static_cast(BV); IGC_ASSERT(BI->getOpWords().size() == 1 && "OpCreatePipeFromPipeStorage takes one argument!"); return mapValue(BI, CastInst::CreateTruncOrBitCast( transValue(BI->getOperand(0), F, BB), transType(BI->getType()), "", BB)); } case OpUnreachable: { return mapValue(BV, new UnreachableInst(*Context, BB)); } case OpLifetimeStart: case OpLifetimeStop: { return mapValue(BV, transLifetimeInst(static_cast(BV), BB, F)); } case OpVectorTimesScalar: { auto BI = static_cast(BV); auto Vector = transValue(BI->getOperand(0), F, BB); auto Scalar = transValue(BI->getOperand(1), F, BB); auto VecType = cast(Vector->getType()); auto Undef = UndefValue::get(VecType); auto ScalarVec = InsertElementInst::Create(Undef, Scalar, ConstantInt::getNullValue(Type::getInt32Ty(*Context)), "", BB); for (unsigned i = 1; i < VecType->getNumElements(); i++) { ScalarVec = InsertElementInst::Create(ScalarVec, Scalar, ConstantInt::get(Type::getInt32Ty(*Context), i), "", BB); } return mapValue(BV, BinaryOperator::CreateFMul(Vector, ScalarVec, "", BB)); } case OpSMod: { auto BI = static_cast(BV); auto *a = transValue(BI->getOperand(0), F, BB); auto *b = transValue(BI->getOperand(1), F, BB); auto *zero = ConstantInt::getNullValue(a->getType()); auto *ShiftAmt = ConstantInt::get( a->getType()->getScalarType(), a->getType()->getScalarSizeInBits() - 1); auto *ShiftOp = isa(a->getType()) ? ConstantVector::getSplat(a->getType()->getVectorNumElements(), ShiftAmt) : ShiftAmt; // OCL C: // // int mod(int a, int b) // { // int out = a % b; // if (((a >> 31) != (b >> 31)) & out != 0) // { // // only add b to out if sign(a) != sign(b) and out != 0. // out += b; // } // // return out; // } // %out = srem %a, %b auto *out = BinaryOperator::CreateSRem(a, b, "", BB); // %sha = ashr %a, 31 auto *sha = BinaryOperator::CreateAShr(a, ShiftOp, "", BB); // %shb = ashr %b, 31 auto *shb = BinaryOperator::CreateAShr(b, ShiftOp, "", BB); // %cmp1 = icmp ne %sha, %shb auto *cmp1 = CmpInst::Create(Instruction::ICmp, llvm::CmpInst::ICMP_NE, sha, shb, "", BB); // %cmp2 = icmp ne %out, 0 auto *cmp2 = CmpInst::Create(Instruction::ICmp, llvm::CmpInst::ICMP_NE, out, zero, "", BB); // %and = and %cmp1, %cmp2 auto *and1 = BinaryOperator::CreateAnd(cmp1, cmp2, "", BB); // %add = add %out, %b auto *add = BinaryOperator::CreateAdd(out, b, "", BB); // %sel = select %and, %add, %out auto *sel = SelectInst::Create(and1, add, out, "", BB); return mapValue(BV, sel); } default: { auto OC = BV->getOpCode(); if (isSPIRVCmpInstTransToLLVMInst(static_cast(BV))) { return mapValue(BV, transCmpInst(BV, BB, F)); } else if (OCLSPIRVBuiltinMap::find(OC) || isIntelSubgroupOpCode(OC)) { return mapValue(BV, transSPIRVBuiltinFromInst( static_cast(BV), BB)); } else if (isBinaryShiftLogicalBitwiseOpCode(OC) || isLogicalOpCode(OC)) { return mapValue(BV, transShiftLogicalBitwiseInst(BV, BB, F)); } else if (isCvtOpCode(OC)) { auto BI = static_cast(BV); Value *Inst = nullptr; if (BI->hasFPRoundingMode() || BI->isSaturatedConversion()) Inst = transSPIRVBuiltinFromInst(BI, BB); else Inst = transConvertInst(BV, F, BB); return mapValue(BV, Inst); } return mapValue(BV, transSPIRVBuiltinFromInst( static_cast(BV), BB)); } IGC_ASSERT_EXIT(0 && "Translation of SPIRV instruction not implemented"); return NULL; } } template bool SPIRVToLLVM::foreachFuncCtlMask(SourceTy Source, FuncTy Func) { SPIRVWord FCM = Source->getFuncCtlMask(); SPIRSPIRVFuncCtlMaskMap::foreach([&](Attribute::AttrKind Attr, SPIRVFunctionControlMaskKind Mask){ if (FCM & Mask) Func(Attr); }); return true; } Function * SPIRVToLLVM::transFunction(SPIRVFunction *BF) { auto Loc = FuncMap.find(BF); if (Loc != FuncMap.end()) return Loc->second; auto IsKernel = BM->isEntryPoint(ExecutionModelKernel, BF->getId()); auto Linkage = IsKernel ? GlobalValue::ExternalLinkage : transLinkageType(BF); FunctionType *FT = dyn_cast(transType(BF->getFunctionType())); Function *F = dyn_cast(mapValue(BF, Function::Create(FT, Linkage, BF->getName(), M))); mapFunction(BF, F); if (BF->hasDecorate(DecorationReferencedIndirectlyINTEL)) F->addFnAttr("referenced-indirectly"); if (!F->isIntrinsic()) { F->setCallingConv(IsKernel ? CallingConv::SPIR_KERNEL : CallingConv::SPIR_FUNC); if (isFuncNoUnwind()) F->addFnAttr(Attribute::NoUnwind); foreachFuncCtlMask(BF, [&](Attribute::AttrKind Attr){ F->addFnAttr(Attr); }); } for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) { auto BA = BF->getArgument(I->getArgNo()); mapValue(BA, &(*I)); const std::string &ArgName = BA->getName(); if (!ArgName.empty()) I->setName(ArgName); BA->foreachAttr([&](SPIRVFuncParamAttrKind Kind){ if (Kind == FunctionParameterAttributeCount) return; F->addAttribute(I->getArgNo() + 1, SPIRSPIRVFuncParamAttrMap::rmap(Kind)); }); } BF->foreachReturnValueAttr([&](SPIRVFuncParamAttrKind Kind){ if (Kind == FunctionParameterAttributeCount) return; F->addAttribute(IGCLLVM::AttributeSet::ReturnIndex, SPIRSPIRVFuncParamAttrMap::rmap(Kind)); }); // Creating all basic blocks before creating instructions. for (size_t I = 0, E = BF->getNumBasicBlock(); I != E; ++I) { transValue(BF->getBasicBlock(I), F, nullptr, true, BoolAction::Noop); } for (size_t I = 0, E = BF->getNumBasicBlock(); I != E; ++I) { SPIRVBasicBlock *BBB = BF->getBasicBlock(I); BasicBlock *BB = dyn_cast(transValue(BBB, F, nullptr, true, BoolAction::Noop)); for (size_t BI = 0, BE = BBB->getNumInst(); BI != BE; ++BI) { SPIRVInstruction *BInst = BBB->getInst(BI); transValue(BInst, F, BB, false, BoolAction::Noop); } } return F; } Value *SPIRVToLLVM::transAsmINTEL(SPIRVAsmINTEL *BA, Function *F, BasicBlock *BB) { bool HasSideEffect = BA->hasDecorate(DecorationSideEffectsINTEL); return InlineAsm::get( dyn_cast(transType(BA->getFunctionType())), BA->getInstructions(), BA->getConstraints(), HasSideEffect, /* IsAlignStack */ false, InlineAsm::AsmDialect::AD_ATT); } CallInst *SPIRVToLLVM::transAsmCallINTEL(SPIRVAsmCallINTEL *BI, Function *F, BasicBlock *BB) { auto *IA = cast(transValue(BI->getAsm(), F, BB)); auto Args = transValue(BM->getValues(BI->getArguments()), F, BB); return CallInst::Create(IA, Args, BI->getName(), BB); } uint64_t SPIRVToLLVM::calcImageType(const SPIRVValue *ImageVal) { const SPIRVTypeImage* TI = nullptr; if (ImageVal->getType()->isTypeSampledImage()) { TI = static_cast(ImageVal->getType())->getImageType(); } else if (ImageVal->getType()->isTypeVmeImageINTEL()) { TI = static_cast(ImageVal->getType())->getImageType(); } else { TI = static_cast(ImageVal->getType()); } const auto &Desc = TI->getDescriptor(); uint64_t ImageType = 0; ImageType |= ((uint64_t)Desc.Dim & 0x7) << 59; ImageType |= ((uint64_t)Desc.Depth & 0x1) << 58; ImageType |= ((uint64_t)Desc.Arrayed & 0x1) << 57; ImageType |= ((uint64_t)Desc.MS & 0x1) << 56; ImageType |= ((uint64_t)Desc.Sampled & 0x3) << 62; ImageType |= ((uint64_t)TI->getAccessQualifier() & 0x3) << 54; return ImageType; } Instruction * SPIRVToLLVM::transSPIRVBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB) { IGC_ASSERT(BB && "Invalid BB"); const auto OC = BI->getOpCode(); auto Ops = BI->getOperands(); // builtins use bool for scalar and ucharx for vector bools. Truncate // or promote as necessary. std::vector operands; for (auto I : Ops) { BoolAction Action = I->getType()->isTypeBool() ? BoolAction::Truncate : BoolAction::Promote; operands.push_back(transValue(I, BB->getParent(), BB, true, Action)); } { // Update image ops to add 'image type' to operands: switch (OC) { case OpSampledImage: case OpVmeImageINTEL: case OpImageRead: case OpImageWrite: case OpImageQuerySize: case OpImageQuerySizeLod: { // resolving argument imageType for // __builtin_spirv_OpSampledImage(%opencl.image2d_t.read_only addrspace(1)* %srcimg0, // i64 imageType, i32 20) Type *pType = Type::getInt64Ty(*Context); uint64_t ImageType = calcImageType(BI->getOperands()[0]); operands.insert(operands.begin() + 1, ConstantInt::get(pType, ImageType)); break; } default: break; } // WA for image inlining: switch (OC) { case OpImageSampleExplicitLod: case OpImageRead: case OpImageWrite: case OpImageQueryFormat: case OpImageQueryOrder: case OpImageQuerySizeLod: case OpImageQuerySize: case OpImageQueryLevels: case OpImageQuerySamples: { auto type = getOrCreateOpaquePtrType(M, "struct.ImageDummy"); auto val = Constant::getNullValue(type); operands.push_back(val); break; } default: break; } } bool hasReturnTypeInTypeList = false; std::string suffix; if (isCvtOpCode(OC)) { hasReturnTypeInTypeList = true; if (BI->isSaturatedConversion() && !(BI->getOpCode() == OpSatConvertSToU || BI->getOpCode() == OpSatConvertUToS)) { suffix += "_Sat"; } SPIRVFPRoundingModeKind kind; std::string rounding_string; if (BI->hasFPRoundingMode(&kind)) { switch (kind) { case FPRoundingModeRTE: rounding_string = "_RTE"; break; case FPRoundingModeRTZ: rounding_string = "_RTZ"; break; case FPRoundingModeRTP: rounding_string = "_RTP"; break; case FPRoundingModeRTN: rounding_string = "_RTN"; break; default: break; } } suffix += rounding_string; } std::vector ArgTys; for (auto &v : operands) { // replace function by function pointer auto *ArgTy = v->getType()->isFunctionTy() ? v->getType()->getPointerTo() : v->getType(); ArgTys.push_back(ArgTy); } // OpImageSampleExplicitLod: SImage | Coordinate | ImageOperands | LOD // OpImageWrite: Image | Image Type | Coordinate | Texel // OpImageRead: Image | Image Type | Coordinate // Look for opaque image pointer operands and convert it with an i64 type for (auto i = 0U; i < BI->getOperands().size(); i++) { SPIRVValue* imagePtr = BI->getOperands()[i]; if (imagePtr->getType()->isTypeImage()) { IGC_ASSERT(isa(transType(imagePtr->getType()))); Value *ImageArgVal = llvm::PtrToIntInst::Create( Instruction::PtrToInt, transValue(imagePtr, BB->getParent(), BB), Type::getInt64Ty(*Context), "ImageArgVal", BB); // replace opaque pointer type with i64 type IGC_ASSERT(ArgTys[i] == transType(imagePtr->getType())); ArgTys[i] = ImageArgVal->getType(); operands[i] = ImageArgVal; } } if (isImageOpCode(OC)) { // Writes have a void return type that is not part of the mangle. if (OC != OpImageWrite) { hasReturnTypeInTypeList = true; } // need to widen coordinate type SPIRVValue* coordinate = BI->getOperands()[1]; Type* coordType = transType(coordinate->getType()); Value *imageCoordinateWiden = nullptr; if (!isa(coordType)) { Value *undef = UndefValue::get(VectorType::get(coordType, 4)); imageCoordinateWiden = InsertElementInst::Create( undef, transValue(coordinate, BB->getParent(), BB), ConstantInt::get(Type::getInt32Ty(*Context), 0), "", BB); } else if (coordType->getVectorNumElements() != 4) { Value *undef = UndefValue::get(coordType); SmallVector shuffleIdx; for (unsigned i = 0; i < coordType->getVectorNumElements(); i++) shuffleIdx.push_back(ConstantInt::get(Type::getInt32Ty(*Context), i)); for (unsigned i = coordType->getVectorNumElements(); i < 4; i++) shuffleIdx.push_back(ConstantInt::get(Type::getInt32Ty(*Context), 0)); imageCoordinateWiden = new ShuffleVectorInst( transValue(coordinate, BB->getParent(), BB), undef, ConstantVector::get(shuffleIdx), "", BB); } if (imageCoordinateWiden != nullptr) { const uint32_t CoordArgIdx = (OC == OpImageSampleExplicitLod) ? 1 : 2; ArgTys[CoordArgIdx] = imageCoordinateWiden->getType(); operands[CoordArgIdx] = imageCoordinateWiden; } } if ((OC == OpImageQuerySizeLod) || (OC == OpImageQuerySize)) { hasReturnTypeInTypeList = true; } Type *RetTy = Type::getVoidTy(*Context); if (BI->hasType()) { auto *pTrans = transType(BI->getType()); RetTy = BI->getType()->isTypeBool() ? truncBoolType(BI->getType(), pTrans) : pTrans; } if (hasReturnTypeInTypeList) { ArgTys.insert(ArgTys.begin(), RetTy); } std::string builtinName(getSPIRVBuiltinName(OC, BI, ArgTys, suffix)); // Fix mangling of VME builtins. if (isIntelVMEOpCode(OC)) { decltype(ArgTys) ArgTysWithVME_WA; for (auto t : ArgTys) { if (isa(t) && t->getPointerElementType()->isStructTy()) { ArgTysWithVME_WA.push_back(t->getPointerElementType()); } else { ArgTysWithVME_WA.push_back(t); } } builtinName = getSPIRVBuiltinName(OC, BI, ArgTysWithVME_WA, suffix); } if (hasReturnTypeInTypeList) { ArgTys.erase(ArgTys.begin()); } Function* Func = M->getFunction(builtinName); FunctionType* FT = FunctionType::get(RetTy, ArgTys, false); if (!Func || Func->getFunctionType() != FT) { Func = Function::Create(FT, GlobalValue::ExternalLinkage, builtinName, M); Func->setCallingConv(CallingConv::SPIR_FUNC); if (isFuncNoUnwind()) Func->addFnAttr(Attribute::NoUnwind); } auto Call = CallInst::Create(Func, operands, "", BB); Call->setName(BI->getName()); setAttrByCalledFunc(Call); return Call; } Type* SPIRVToLLVM::getNamedBarrierType() { if (!m_NamedBarrierType) { llvm::SmallVector NamedBarrierSturctType(3, Type::getInt32Ty(*Context)); m_NamedBarrierType = StructType::create(*Context, NamedBarrierSturctType, "struct.__namedBarrier")->getPointerTo(SPIRAS_Local); } return m_NamedBarrierType; } bool SPIRVToLLVM::translate() { if (!transAddressingModel()) return false; compileUnit = DbgTran.createCompileUnit(); for (unsigned I = 0, E = BM->getNumVariables(); I != E; ++I) { auto BV = BM->getVariable(I); if (BV->getStorageClass() != StorageClassFunction) transValue(BV, nullptr, nullptr, true, BoolAction::Noop); } for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) { transFunction(BM->getFunction(I)); } for(auto& funcs : FuncMap) { auto diSP = getDbgTran().getDISP(funcs.first->getId()); if (diSP) funcs.second->setSubprogram(diSP); } if (!transKernelMetadata()) return false; if (!transFPContractMetadata()) return false; if (!transSourceLanguage()) return false; if (!transSourceExtension()) return false; if (!transOCLBuiltinsFromVariables()) return false; if (!postProcessOCL()) return false; DbgTran.transGlobals(); DbgTran.finalize(); return true; } bool SPIRVToLLVM::transAddressingModel() { switch (BM->getAddressingModel()) { case AddressingModelPhysical64: M->setTargetTriple(SPIR_TARGETTRIPLE64); M->setDataLayout(SPIR_DATALAYOUT64); break; case AddressingModelPhysical32: M->setTargetTriple(SPIR_TARGETTRIPLE32); M->setDataLayout(SPIR_DATALAYOUT32); break; case AddressingModelLogical: // Do not set target triple and data layout break; default: SPIRVCKRT(0, InvalidAddressingModel, "Actual addressing mode is " + (unsigned)BM->getAddressingModel()); } return true; } bool SPIRVToLLVM::transDecoration(SPIRVValue *BV, Value *V) { if (!transAlign(BV, V)) return false; DbgTran.transDbgInfo(BV, V); return true; } bool SPIRVToLLVM::transFPContractMetadata() { bool ContractOff = false; for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) { SPIRVFunction *BF = BM->getFunction(I); if (!isOpenCLKernel(BF)) continue; if (BF->getExecutionMode(ExecutionModeContractionOff)) { ContractOff = true; break; } } if (!ContractOff) M->getOrInsertNamedMetadata(spv::kSPIR2MD::FPContract); return true; } std::string SPIRVToLLVM::transOCLImageTypeAccessQualifier( spv::SPIRVTypeImage* ST) { return SPIRSPIRVAccessQualifierMap::rmap(ST->getAccessQualifier()); } Type * SPIRVToLLVM::decodeVecTypeHint(LLVMContext &C, unsigned code) { unsigned VecWidth = code >> 16; unsigned Scalar = code & 0xFFFF; Type *ST = nullptr; switch (Scalar) { case 0: case 1: case 2: case 3: ST = IntegerType::get(C, 1 << (3 + Scalar)); break; case 4: ST = Type::getHalfTy(C); break; case 5: ST = Type::getFloatTy(C); break; case 6: ST = Type::getDoubleTy(C); break; default: llvm_unreachable("Invalid vec type hint"); } if (VecWidth < 1) return ST; return VectorType::get(ST, VecWidth); } // Information of types of kernel arguments may be additionally stored in // 'OpString "kernel_arg_type.%kernel_name%.type1,type2,type3,..' instruction. // Try to find such instruction and generate metadata based on it. static bool transKernelArgTypeMedataFromString( LLVMContext *Ctx, std::vector &KernelMD, SPIRVModule *BM, Function *Kernel) { std::string ArgTypePrefix = std::string(SPIR_MD_KERNEL_ARG_TYPE) + "." + Kernel->getName().str() + "."; auto ArgTypeStrIt = std::find_if( BM->getStringVec().begin(), BM->getStringVec().end(), [=](SPIRVString *S) { return S->getStr().find(ArgTypePrefix) == 0; }); if (ArgTypeStrIt == BM->getStringVec().end()) return false; std::string ArgTypeStr = (*ArgTypeStrIt)->getStr().substr(ArgTypePrefix.size()); std::vector TypeMDs; TypeMDs.push_back(MDString::get(*Ctx, SPIR_MD_KERNEL_ARG_TYPE)); int countBraces = 0; std::string::size_type start = 0; for (std::string::size_type i = 0; i < ArgTypeStr.length(); i++) { switch (ArgTypeStr[i]) { case '<': countBraces++; break; case '>': countBraces--; break; case ',': if (countBraces == 0) { TypeMDs.push_back(MDString::get(*Ctx, ArgTypeStr.substr(start, i - start))); start = i + 1; } } } KernelMD.push_back(MDNode::get(*Ctx, TypeMDs)); return true; } bool SPIRVToLLVM::transKernelMetadata() { IGC::ModuleMetaData MD; NamedMDNode *KernelMDs = M->getOrInsertNamedMetadata(SPIR_MD_KERNELS); for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) { SPIRVFunction *BF = BM->getFunction(I); Function *F = static_cast(getTranslatedValue(BF)); IGC_ASSERT(F && "Invalid translated function"); // __attribute__((annotate("some_user_annotation"))) are passed via // UserSemantic decoration on functions. if (BF->hasDecorate(DecorationUserSemantic)) { auto &funcInfo = MD.FuncMD[F]; funcInfo.UserAnnotations = BF->getDecorationStringLiteral(DecorationUserSemantic); } if (F->getCallingConv() != CallingConv::SPIR_KERNEL || F->isDeclaration()) continue; std::vector KernelMD; KernelMD.push_back(ValueAsMetadata::get(F)); // Generate metadata for kernel_arg_address_spaces addOCLKernelArgumentMetadata(Context, KernelMD, SPIR_MD_KERNEL_ARG_ADDR_SPACE, BF, [=](SPIRVFunctionParameter *Arg){ SPIRVType *ArgTy = Arg->getType(); SPIRAddressSpace AS = SPIRAS_Private; if (ArgTy->isTypePointer()) AS = SPIRSPIRVAddrSpaceMap::rmap(ArgTy->getPointerStorageClass()); else if (ArgTy->isTypeOCLImage() || ArgTy->isTypePipe()) AS = SPIRAS_Global; return ConstantAsMetadata::get( ConstantInt::get(Type::getInt32Ty(*Context), AS)); }); // Generate metadata for kernel_arg_access_qual addOCLKernelArgumentMetadata(Context, KernelMD, SPIR_MD_KERNEL_ARG_ACCESS_QUAL, BF, [=](SPIRVFunctionParameter *Arg){ std::string Qual; auto T = Arg->getType(); if (T->isTypeOCLImage()) { auto ST = static_cast(T); Qual = transOCLImageTypeAccessQualifier(ST); } else if (T->isTypePipe()){ auto PT = static_cast(T); Qual = transOCLPipeTypeAccessQualifier(PT); } else Qual = "none"; return MDString::get(*Context, Qual); }); // Generate metadata for kernel_arg_type if (!transKernelArgTypeMedataFromString(Context, KernelMD, BM, F)) { addOCLKernelArgumentMetadata(Context, KernelMD, SPIR_MD_KERNEL_ARG_TYPE, BF, [=](SPIRVFunctionParameter *Arg) { return transOCLKernelArgTypeName(Arg); }); } // Generate metadata for kernel_arg_type_qual addOCLKernelArgumentMetadata(Context, KernelMD, SPIR_MD_KERNEL_ARG_TYPE_QUAL, BF, [=](SPIRVFunctionParameter *Arg){ std::string Qual; if (Arg->hasDecorate(DecorationVolatile)) Qual = kOCLTypeQualifierName::Volatile; Arg->foreachAttr([&](SPIRVFuncParamAttrKind Kind){ Qual += Qual.empty() ? "" : " "; switch (Kind){ case FunctionParameterAttributeNoAlias: Qual += kOCLTypeQualifierName::Restrict; break; case FunctionParameterAttributeNoWrite: Qual += kOCLTypeQualifierName::Const; break; default: // do nothing. break; } }); if (Arg->getType()->isTypePipe()) { Qual += Qual.empty() ? "" : " "; Qual += kOCLTypeQualifierName::Pipe; } return MDString::get(*Context, Qual); }); // Generate metadata for kernel_arg_base_type addOCLKernelArgumentMetadata(Context, KernelMD, SPIR_MD_KERNEL_ARG_BASE_TYPE, BF, [=](SPIRVFunctionParameter *Arg){ return transOCLKernelArgTypeName(Arg); }); // Generate metadata for kernel_arg_name bool ArgHasName = true; BF->foreachArgument([&](SPIRVFunctionParameter *Arg) { ArgHasName &= !Arg->getName().empty(); }); if (ArgHasName) addOCLKernelArgumentMetadata(Context, KernelMD, SPIR_MD_KERNEL_ARG_NAME, BF, [=](SPIRVFunctionParameter *Arg) { return MDString::get(*Context, Arg->getName()); }); // Generate metadata for reqd_work_group_size if (auto EM = BF->getExecutionMode(ExecutionModeLocalSize)) { KernelMD.push_back(getMDNodeStringIntVec(Context, spv::kSPIR2MD::WGSize, EM->getLiterals())); } // Generate metadata for work_group_size_hint if (auto EM = BF->getExecutionMode(ExecutionModeLocalSizeHint)) { KernelMD.push_back(getMDNodeStringIntVec(Context, spv::kSPIR2MD::WGSizeHint, EM->getLiterals())); } // Generate metadata for vec_type_hint if (auto EM = BF->getExecutionMode(ExecutionModeVecTypeHint)) { std::vector MetadataVec; MetadataVec.push_back(MDString::get(*Context, spv::kSPIR2MD::VecTyHint)); Type *VecHintTy = decodeVecTypeHint(*Context, EM->getLiterals()[0]); MetadataVec.push_back(ValueAsMetadata::get(UndefValue::get(VecHintTy))); MetadataVec.push_back( ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), 0))); KernelMD.push_back(MDNode::get(*Context, MetadataVec)); } auto &funcInfo = MD.FuncMD[F]; // Generate metadata for initializer if (BF->getExecutionMode(ExecutionModeInitializer)) { funcInfo.IsInitializer = true; } // Generate metadata for finalizer if (BF->getExecutionMode(ExecutionModeFinalizer)) { funcInfo.IsFinalizer = true; } // Generate metadata for SubgroupSize if (auto EM = BF->getExecutionMode(ExecutionModeSubgroupSize)) { unsigned subgroupSize = EM->getLiterals()[0]; std::vector MetadataVec; MetadataVec.push_back(MDString::get(*Context, spv::kSPIR2MD::ReqdSubgroupSize)); MetadataVec.push_back( ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), subgroupSize))); KernelMD.push_back(MDNode::get(*Context, MetadataVec)); } // Generate metadata for SubgroupsPerWorkgroup if (auto EM = BF->getExecutionMode(ExecutionModeSubgroupsPerWorkgroup)) { funcInfo.CompiledSubGroupsNumber = EM->getLiterals()[0]; } // Generate metadata for MaxByteOffset decorations { bool ArgHasMaxByteOffset = false; BF->foreachArgument([&](SPIRVFunctionParameter *Arg) { SPIRVWord offset; ArgHasMaxByteOffset |= Arg->hasMaxByteOffset(offset); }); if (ArgHasMaxByteOffset) { BF->foreachArgument([&](SPIRVFunctionParameter *Arg) { SPIRVWord offset; bool ok = Arg->hasMaxByteOffset(offset); // If the decoration is not present on an argument of the function, // encode that as a zero in the metadata. That currently seems // like a degenerate case wouldn't be worth optimizing. unsigned val = ok ? offset : 0; funcInfo.maxByteOffsets.push_back(val); }); } } llvm::MDNode *Node = MDNode::get(*Context, KernelMD); KernelMDs->addOperand(Node); } IGC::serialize(MD, M); return true; } bool SPIRVToLLVM::transAlign(SPIRVValue *BV, Value *V) { if (auto AL = dyn_cast(V)) { SPIRVWord Align = 0; if (BV->hasAlignment(&Align)) AL->setAlignment(MaybeAlign(Align)); return true; } if (auto GV = dyn_cast(V)) { SPIRVWord Align = 0; if (BV->hasAlignment(&Align)) GV->setAlignment(MaybeAlign(Align)); return true; } return true; } void SPIRVToLLVM::transOCLVectorLoadStore(std::string& UnmangledName, std::vector &BArgs) { if (UnmangledName.find("vload") == 0 && UnmangledName.find("n") != std::string::npos) { if (BArgs.back() > 1) { std::stringstream SS; SS << BArgs.back(); UnmangledName.replace(UnmangledName.find("n"), 1, SS.str()); } else { UnmangledName.erase(UnmangledName.find("n"), 1); } BArgs.pop_back(); } else if (UnmangledName.find("vstore") == 0) { if (UnmangledName.find("n") != std::string::npos) { auto T = BM->getValueType(BArgs[0]); if (T->isTypeVector()) { auto W = T->getVectorComponentCount(); std::stringstream SS; SS << W; UnmangledName.replace(UnmangledName.find("n"), 1, SS.str()); } else { UnmangledName.erase(UnmangledName.find("n"), 1); } } if (UnmangledName.find("_r") != std::string::npos) { UnmangledName.replace(UnmangledName.find("_r"), 2, std::string("_") + SPIRSPIRVFPRoundingModeMap::rmap(static_cast( BArgs.back()))); BArgs.pop_back(); } } } Instruction* SPIRVToLLVM::transDebugInfo(SPIRVExtInst* BC, BasicBlock* BB) { if (!BC) return nullptr; auto extOp = (OCLExtOpDbgKind)BC->getExtOp(); switch (extOp) { case OCLExtOpDbgKind::DbgDcl: { OpDebugDeclare dbgDcl(BC); auto lvar = dbgDcl.getLocalVar(); SPIRVValue* spirvVal = static_cast(BM->getEntry(lvar)); SPIRVToLLVMValueMap::iterator Loc = ValueMap.find(spirvVal); if (Loc != ValueMap.end()) { return DbgTran.createDbgDeclare(BC, Loc->second, BB); } break; } case OCLExtOpDbgKind::DbgVal: { OpDebugValue dbgValue(BC); auto lvar = dbgValue.getValueVar(); SPIRVValue* spirvVal = static_cast(BM->getEntry(lvar)); SPIRVToLLVMValueMap::iterator Loc = ValueMap.find(spirvVal); if (Loc != ValueMap.end()) { return DbgTran.createDbgValue(BC, Loc->second, BB); } break; } default: break; } return nullptr; } Instruction * SPIRVToLLVM::transOCLBuiltinFromExtInst(SPIRVExtInst *BC, BasicBlock *BB) { IGC_ASSERT(BB && "Invalid BB"); SPIRVWord EntryPoint = BC->getExtOp(); SPIRVExtInstSetKind Set = BM->getBuiltinSet(BC->getExtSetId()); bool IsPrintf = false; std::string FuncName; if (Set == SPIRVEIS_DebugInfo) { return transDebugInfo(BC, BB); } IGC_ASSERT(Set == SPIRVEIS_OpenCL && "Not OpenCL extended instruction"); if (EntryPoint == OpenCLLIB::printf) IsPrintf = true; else { FuncName = OCLExtOpMap::map(static_cast( EntryPoint)); } auto BArgs = BC->getArguments(); transOCLVectorLoadStore(FuncName, BArgs); // keep builtin functions written with bool as i1, truncate down if necessary. auto Args = transValue(BC->getValues(BArgs), BB->getParent(), BB, BoolAction::Truncate); std::vector ArgTypes; for (auto &v : Args) { ArgTypes.push_back(v->getType()); } bool IsVarArg = false; if (IsPrintf) { FuncName = "printf"; IsVarArg = true; ArgTypes.resize(1); } else { decorateSPIRVExtInst(FuncName, ArgTypes); } FunctionType *FT = FunctionType::get( truncBoolType(BC->getType(), transType(BC->getType())), ArgTypes, IsVarArg); Function *F = M->getFunction(FuncName); if (!F) { F = Function::Create(FT, GlobalValue::ExternalLinkage, FuncName, M); F->setCallingConv(CallingConv::SPIR_FUNC); if (isFuncNoUnwind()) F->addFnAttr(Attribute::NoUnwind); } CallInst *Call = CallInst::Create(F, Args, BC->getName(), BB); setCallingConv(Call); Call->addAttribute(IGCLLVM::AttributeSet::FunctionIndex, Attribute::NoUnwind); return Call; } // SPIR-V only contains language version. Use OpenCL language version as // SPIR version. bool SPIRVToLLVM::transSourceLanguage() { SPIRVWord Ver = 0; SpvSourceLanguage Lang = BM->getSourceLanguage(&Ver); IGC_ASSERT((Lang == SpvSourceLanguageOpenCL_C || Lang == SpvSourceLanguageOpenCL_CPP) && "Unsupported source language"); unsigned short Major = 0; unsigned char Minor = 0; unsigned char Rev = 0; std::tie(Major, Minor, Rev) = decodeOCLVer(Ver); addOCLVersionMetadata(Context, M, kSPIR2MD::SPIRVer, Major, Minor); addOCLVersionMetadata(Context, M, kSPIR2MD::OCLVer, Major, Minor); return true; } bool SPIRVToLLVM::transSourceExtension() { auto ExtSet = rmap(BM->getExtension()); auto CapSet = rmap(BM->getCapability()); for (auto &I:CapSet) ExtSet.insert(I); auto OCLExtensions = getStr(map(ExtSet)); std::string OCLOptionalCoreFeatures; bool First = true; static const char *OCLOptCoreFeatureNames[] = { "cl_images", "cl_doubles", }; for (auto &I:OCLOptCoreFeatureNames) { size_t Loc = OCLExtensions.find(I); if (Loc != std::string::npos) { OCLExtensions.erase(Loc, strlen(I)); if (First) First = false; else OCLOptionalCoreFeatures += ' '; OCLOptionalCoreFeatures += I; } } addNamedMetadataString(Context, M, kSPIR2MD::Extensions, OCLExtensions); addNamedMetadataString(Context, M, kSPIR2MD::OptFeatures, OCLOptionalCoreFeatures); return true; } __attr_unused static void dumpSPIRVBC(const char* fname, const char* data, unsigned int size) { FILE* fp; fp = fopen(fname, "wb"); if(fp != NULL) { fwrite(data, 1, size, fp); fclose(fp); } } bool ReadSPIRV(LLVMContext &C, std::istream &IS, Module *&M, std::string &ErrMsg, std::unordered_map *specConstants) { std::unique_ptr BM( SPIRVModule::createSPIRVModule() ); BM->setSpecConstantMap(specConstants); IS >> *BM; BM->resolveUnknownStructFields(); M = new Module( "",C ); SPIRVToLLVM BTL( M,BM.get() ); bool Succeed = true; if(!BTL.translate()) { BM->getError( ErrMsg ); Succeed = false; } llvm::legacy::PassManager PM; PM.add( new TypesLegalizationPass() ); PM.add( createDeadCodeEliminationPass() ); PM.run( *M ); #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) if (DbgSaveTmpLLVM) dumpLLVM(M, DbgTmpLLVMFileName); #endif if (!Succeed) { delete M; M = nullptr; } return Succeed; } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/SPIRVUtil.cpp000066400000000000000000000317401363533017100247440ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVUtil.cpp - SPIR-V Utilities -------------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines utility classes and functions shared by SPIR-V /// reader/writer. /// //===----------------------------------------------------------------------===// #include "common/LLVMWarningsPush.hpp" #include "llvmWrapper/Bitcode/BitcodeWriter.h" #include "llvmWrapper/IR/Attributes.h" #include "llvmWrapper/Support/ToolOutputFile.h" #include #include "llvm/ADT/StringExtras.h" #include "llvm/Transforms/Utils/Cloning.h" #include "common/LLVMWarningsPop.hpp" #include "libSPIRV/SPIRVInstruction.h" #include "SPIRVInternal.h" #include "Mangler/ParameterType.h" #include "Probe.h" namespace spv{ void saveLLVMModule(Module *M, const std::string &OutputFile) { std::error_code EC; IGCLLVM::tool_output_file Out(OutputFile.c_str(), EC, sys::fs::F_None); IGC_ASSERT_EXIT((!EC) && "Failed to open file"); IGCLLVM::WriteBitcodeToFile(M, Out.os()); Out.keep(); } PointerType* getOrCreateOpaquePtrType(Module *M, const std::string &Name, unsigned AddrSpace) { auto OpaqueType = M->getTypeByName(Name); if (!OpaqueType) OpaqueType = StructType::create(M->getContext(), Name); return PointerType::get(OpaqueType, AddrSpace); } void getFunctionTypeParameterTypes(llvm::FunctionType* FT, std::vector& ArgTys) { for (auto I = FT->param_begin(), E = FT->param_end(); I != E; ++I) { ArgTys.push_back(*I); } } Function * getOrCreateFunction(Module *M, Type *RetTy, ArrayRef ArgTypes, StringRef Name, bool builtin, IGCLLVM::AttributeSet *Attrs, bool takeName) { std::string FuncName(Name); if (builtin) decorateSPIRVBuiltin(FuncName, ArgTypes); FunctionType *FT = FunctionType::get( RetTy, ArgTypes, false); Function *F = M->getFunction(FuncName); if (!F || F->getFunctionType() != FT) { auto NewF = Function::Create(FT, GlobalValue::ExternalLinkage, FuncName, M); if (F && takeName) NewF->takeName(F); F = NewF; F->setCallingConv(CallingConv::SPIR_FUNC); if (Attrs) F->setAttributes(*Attrs); } return F; } std::vector getArguments(CallInst* CI) { std::vector Args; for (unsigned I = 0, E = CI->getNumArgOperands(); I != E; ++I) { Args.push_back(CI->getArgOperand(I)); } return Args; } std::string recursive_mangle(const Type* pType) { Type::TypeID ID = pType->getTypeID(); switch (ID) { case Type::FloatTyID: return "f32"; case Type::DoubleTyID: return "f64"; case Type::HalfTyID: return "f16"; case Type::IntegerTyID: return "i" + utostr(pType->getIntegerBitWidth()); case Type::VectorTyID: { unsigned int vecLen = pType->getVectorNumElements(); Type* pEltType = pType->getVectorElementType(); return "v" + utostr(vecLen) + recursive_mangle(pEltType); } case Type::PointerTyID: { unsigned int AS = pType->getPointerAddressSpace(); Type* pPointeeType = pType->getPointerElementType(); if (isa(pPointeeType) && cast(pPointeeType)->isOpaque()) { return "i64"; } return "p" + utostr(AS) + recursive_mangle(pPointeeType); } case Type::StructTyID: { auto structName = cast(pType)->getName(); auto pointPos = structName.rfind('.'); return pointPos != structName.npos ? structName.substr(pointPos + 1) : structName; } case Type::FunctionTyID: { return "func"; } case Type::ArrayTyID: { auto elemType = pType->getArrayElementType(); auto numElems = pType->getArrayNumElements(); return "a" + utostr(numElems) + recursive_mangle(elemType); } default: IGC_ASSERT_EXIT(0 && "unhandled type to mangle!"); return ""; } } std::string Mangler(const std::string &FuncName, const std::vector &ArgTypes) { std::string str_type; for (auto U : ArgTypes) { str_type += "_" + recursive_mangle(U); } return FuncName + str_type; } void decorateSPIRVBuiltin(std::string &S) { S = std::string(kLLVMName::builtinPrefix) + S; } void decorateSPIRVBuiltin(std::string &S, std::vector ArgTypes) { S.assign(std::string(kLLVMName::builtinPrefix) + Mangler(S,ArgTypes)); } void decorateSPIRVExtInst(std::string &S, std::vector ArgTypes) { S.assign(std::string(kLLVMName::builtinExtInstPrefixOpenCL) + Mangler(S,ArgTypes)); } bool isFunctionBuiltin(llvm::Function* F) { return F && F->isDeclaration() && F->getName().startswith(kLLVMName::builtinPrefix); } std::string getSPIRVBuiltinName(Op OC, SPIRVInstruction *BI, std::vector ArgTypes, std::string suffix) { std::string name = ""; bool hasI32Postfix = false; if (isIntelSubgroupOpCode(OC)) { std::stringstream tmpName; SPIRVType *DataTy = nullptr; switch (OC) { case OpSubgroupBlockReadINTEL: case OpSubgroupImageBlockReadINTEL: tmpName << "intel_sub_group_block_read"; DataTy = BI->getType(); break; case OpSubgroupBlockWriteINTEL: tmpName << "intel_sub_group_block_write"; DataTy = BI->getOperands()[1]->getType(); break; case OpSubgroupImageBlockWriteINTEL: tmpName << "intel_sub_group_block_write"; DataTy = BI->getOperands()[2]->getType(); break; case OpSubgroupImageMediaBlockReadINTEL: tmpName << OCLSPIRVBuiltinMap::map(OC); DataTy = BI->getType(); hasI32Postfix = true; break; case OpSubgroupImageMediaBlockWriteINTEL: tmpName << OCLSPIRVBuiltinMap::map(OC); DataTy = (*BI->getOperands().rbegin())->getType(); hasI32Postfix = true; break; default: tmpName << OCLSPIRVBuiltinMap::map(OC); } if (DataTy) { if (DataTy->getBitWidth() == 8) { tmpName << "_uc"; } else if (DataTy->getBitWidth() == 16) { tmpName << "_us"; } else if (DataTy->getBitWidth() == 32 && hasI32Postfix) { tmpName << "_ui"; } else if (DataTy->getBitWidth() == 64) { tmpName << "_ul"; } if (DataTy->isTypeVector()) { if (unsigned ComponentCount = DataTy->getVectorComponentCount()) tmpName << ComponentCount; } } name = tmpName.str(); } else { name = OCLSPIRVBuiltinMap::map(OC); } if (!name.empty()) { name = name + suffix; decorateSPIRVBuiltin(name, ArgTypes); } else { IGC_ASSERT_EXIT(0 && "Couldn't find opcode in map!"); } return name; } CallInst * mutateCallInst(Module *M, CallInst *CI, std::function &)>ArgMutate, bool Mangle, IGCLLVM::AttributeSet *Attrs, bool TakeFuncName) { auto Args = getArguments(CI); auto NewName = ArgMutate(CI, Args); std::string InstName; if (!CI->getType()->isVoidTy() && CI->hasName()) { InstName = CI->getName(); CI->setName(InstName + ".old"); } auto NewCI = addCallInst(M, NewName, CI->getType(), Args, Attrs, CI, Mangle, InstName, TakeFuncName); Function* OldF = CI->getCalledFunction(); Function* NewF = NewCI->getCalledFunction(); if (!OldF->isDeclaration() && NewF->isDeclaration()) { // This means that we need to clone the old function into new one. // It is needed because when Clang is compiling to llvm-bc it does the same thing. // If we want to link with such modules, we need to make the behaviour similar. IGC_ASSERT(OldF->getNumOperands() == NewF->getNumOperands()); ValueToValueMapTy VMap; llvm::SmallVector Returns; BasicBlock* EntryBB = BasicBlock::Create(M->getContext(), "", NewF); IRBuilder<> builder(EntryBB); for (auto OldArgIt = OldF->arg_begin(), NewArgIt = NewF->arg_begin(); OldArgIt != OldF->arg_end(); ++OldArgIt, ++NewArgIt) { NewArgIt->setName(OldArgIt->getName()); if (OldArgIt->getType() == NewArgIt->getType()) { VMap[&*OldArgIt] = &*NewArgIt; } else { IGC_ASSERT(NewArgIt->getType()->isPointerTy()); LoadInst* Load = builder.CreateLoad(&*NewArgIt); VMap[&*OldArgIt] = Load; } } CloneFunctionInto(NewF, OldF, VMap, true, Returns); // Merge the basic block with Load instruction with the original entry basic block. BasicBlock* ClonedEntryBB = cast(VMap[&*OldF->begin()]); builder.CreateBr(ClonedEntryBB); } CI->replaceAllUsesWith(NewCI); CI->dropAllReferences(); CI->removeFromParent(); return NewCI; } void mutateFunction(Function *F, std::function &)>ArgMutate, bool Mangle, IGCLLVM::AttributeSet *Attrs, bool TakeFuncName) { auto M = F->getParent(); for (auto I = F->user_begin(), E = F->user_end(); I != E;) { if (auto CI = dyn_cast(*I++)) mutateCallInst(M, CI, ArgMutate, Mangle, Attrs, TakeFuncName); } if (F->use_empty()) { F->dropAllReferences(); F->removeFromParent(); } } CallInst * addCallInst(Module *M, StringRef FuncName, Type *RetTy, ArrayRef Args, IGCLLVM::AttributeSet *Attrs, Instruction *Pos, bool Mangle, StringRef InstName, bool TakeFuncName) { auto F = getOrCreateFunction(M, RetTy, getTypes(Args), FuncName, Mangle, Attrs, TakeFuncName); auto CI = CallInst::Create(F, Args, InstName, Pos); CI->setCallingConv(F->getCallingConv()); return CI; } ConstantInt * getInt64(Module *M, int64_t value) { return ConstantInt::get(Type::getInt64Ty(M->getContext()), value, true); } ConstantInt * getInt32(Module *M, int value) { return ConstantInt::get(Type::getInt32Ty(M->getContext()), value, true); } std::tuple decodeOCLVer(unsigned Ver) { unsigned short Major = Ver / 100000; unsigned char Minor = (Ver % 100000) / 1000; unsigned char Rev = Ver % 1000; return std::make_tuple(Major, Minor, Rev); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/SPIRVconsum.h000066400000000000000000000040561363533017100250000ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVconsum.h - entry point for SPIR-V to LLVM ------------*- C++ -*-===// // // The LLVM/SPIR-V Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// This file implements conversion of SPIR-V binary to LLVM IR. /// //===----------------------------------------------------------------------===// #ifndef SPIRVCONSUM_HPP_ #define SPIRVCONSUM_HPP_ #include "llvm/IR/Module.h" #include namespace spv{ // Loads SPIRV from istream and translate to LLVM module. // Returns true if succeeds. bool ReadSPIRV(llvm::LLVMContext &C, std::istream &IS, llvm::Module *&M, std::string &ErrMsg, std::unordered_map *specConstants); } #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/000077500000000000000000000000001363533017100240645ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/OpenCL.std.h000066400000000000000000000053171363533017100261540ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ /* ** Copyright (c) 2015 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and/or associated documentation files (the "Materials"), ** to deal in the Materials without restriction, including without limitation ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** and/or sell copies of the Materials, and to permit persons to whom the ** Materials are furnished to do so, subject to the following conditions: ** ** The above copyright notice and this permission notice shall be included in ** all copies or substantial portions of the Materials. ** ** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS ** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND ** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ ** ** THE MATERIALS ARE 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 AND NONINFRINGEMENT. IN NO EVENT SHALL ** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS ** IN THE MATERIALS. */ namespace OpenCLLIB { enum Entrypoints { #define _OCL_EXT_OP(name, num) name = num, #include "OpenCL.stdfuncs.h" #undef _OCL_EXT_OP }; }; // end namespace OpenCL20 intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/OpenCL.stdfuncs.h000066400000000000000000000125261363533017100272130ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // math functions _OCL_EXT_OP(acos, 0) _OCL_EXT_OP(acosh, 1) _OCL_EXT_OP(acospi, 2) _OCL_EXT_OP(asin, 3) _OCL_EXT_OP(asinh, 4) _OCL_EXT_OP(asinpi, 5) _OCL_EXT_OP(atan, 6) _OCL_EXT_OP(atan2, 7) _OCL_EXT_OP(atanh, 8) _OCL_EXT_OP(atanpi, 9) _OCL_EXT_OP(atan2pi, 10) _OCL_EXT_OP(cbrt, 11) _OCL_EXT_OP(ceil, 12) _OCL_EXT_OP(copysign, 13) _OCL_EXT_OP(cos, 14) _OCL_EXT_OP(cosh, 15) _OCL_EXT_OP(cospi, 16) _OCL_EXT_OP(erfc, 17) _OCL_EXT_OP(erf, 18) _OCL_EXT_OP(exp, 19) _OCL_EXT_OP(exp2, 20) _OCL_EXT_OP(exp10, 21) _OCL_EXT_OP(expm1, 22) _OCL_EXT_OP(fabs, 23) _OCL_EXT_OP(fdim, 24) _OCL_EXT_OP(floor, 25) _OCL_EXT_OP(fma, 26) _OCL_EXT_OP(fmax, 27) _OCL_EXT_OP(fmin, 28) _OCL_EXT_OP(fmod, 29) _OCL_EXT_OP(fract, 30) _OCL_EXT_OP(frexp, 31) _OCL_EXT_OP(hypot, 32) _OCL_EXT_OP(ilogb, 33) _OCL_EXT_OP(ldexp, 34) _OCL_EXT_OP(lgamma, 35) _OCL_EXT_OP(lgamma_r, 36) _OCL_EXT_OP(log, 37) _OCL_EXT_OP(log2, 38) _OCL_EXT_OP(log10, 39) _OCL_EXT_OP(log1p, 40) _OCL_EXT_OP(logb, 41) _OCL_EXT_OP(mad, 42) _OCL_EXT_OP(maxmag, 43) _OCL_EXT_OP(minmag, 44) _OCL_EXT_OP(modf, 45) _OCL_EXT_OP(nan, 46) _OCL_EXT_OP(nextafter, 47) _OCL_EXT_OP(pow, 48) _OCL_EXT_OP(pown, 49) _OCL_EXT_OP(powr, 50) _OCL_EXT_OP(remainder, 51) _OCL_EXT_OP(remquo, 52) _OCL_EXT_OP(rint, 53) _OCL_EXT_OP(rootn, 54) _OCL_EXT_OP(round, 55) _OCL_EXT_OP(rsqrt, 56) _OCL_EXT_OP(sin, 57) _OCL_EXT_OP(sincos, 58) _OCL_EXT_OP(sinh, 59) _OCL_EXT_OP(sinpi, 60) _OCL_EXT_OP(sqrt, 61) _OCL_EXT_OP(tan, 62) _OCL_EXT_OP(tanh, 63) _OCL_EXT_OP(tanpi, 64) _OCL_EXT_OP(tgamma, 65) _OCL_EXT_OP(trunc, 66) _OCL_EXT_OP(half_cos, 67) _OCL_EXT_OP(half_divide, 68) _OCL_EXT_OP(half_exp, 69) _OCL_EXT_OP(half_exp2, 70) _OCL_EXT_OP(half_exp10, 71) _OCL_EXT_OP(half_log, 72) _OCL_EXT_OP(half_log2, 73) _OCL_EXT_OP(half_log10, 74) _OCL_EXT_OP(half_powr, 75) _OCL_EXT_OP(half_recip, 76) _OCL_EXT_OP(half_rsqrt, 77) _OCL_EXT_OP(half_sin, 78) _OCL_EXT_OP(half_sqrt, 79) _OCL_EXT_OP(half_tan, 80) _OCL_EXT_OP(native_cos, 81) _OCL_EXT_OP(native_divide, 82) _OCL_EXT_OP(native_exp, 83) _OCL_EXT_OP(native_exp2, 84) _OCL_EXT_OP(native_exp10, 85) _OCL_EXT_OP(native_log, 86) _OCL_EXT_OP(native_log2, 87) _OCL_EXT_OP(native_log10, 88) _OCL_EXT_OP(native_powr, 89) _OCL_EXT_OP(native_recip, 90) _OCL_EXT_OP(native_rsqrt, 91) _OCL_EXT_OP(native_sin, 92) _OCL_EXT_OP(native_sqrt, 93) _OCL_EXT_OP(native_tan, 94) // Common _OCL_EXT_OP(fclamp, 95) _OCL_EXT_OP(degrees, 96) _OCL_EXT_OP(mix, 99) _OCL_EXT_OP(fmax_common, 97) _OCL_EXT_OP(fmin_common, 98) _OCL_EXT_OP(radians, 100) _OCL_EXT_OP(step, 101) _OCL_EXT_OP(smoothstep, 102) _OCL_EXT_OP(sign, 103) // Geometrics _OCL_EXT_OP(cross, 104) _OCL_EXT_OP(distance, 105) _OCL_EXT_OP(length, 106) _OCL_EXT_OP(normalize, 107) _OCL_EXT_OP(fast_distance, 108) _OCL_EXT_OP(fast_length, 109) _OCL_EXT_OP(fast_normalize, 110) // Integers _OCL_EXT_OP(s_abs, 141) _OCL_EXT_OP(s_abs_diff, 142) _OCL_EXT_OP(s_add_sat, 143) _OCL_EXT_OP(u_add_sat, 144) _OCL_EXT_OP(s_hadd, 145) _OCL_EXT_OP(u_hadd, 146) _OCL_EXT_OP(s_rhadd, 147) _OCL_EXT_OP(u_rhadd, 148) _OCL_EXT_OP(s_clamp, 149) _OCL_EXT_OP(u_clamp, 150) _OCL_EXT_OP(clz, 151) _OCL_EXT_OP(ctz, 152) _OCL_EXT_OP(s_mad_hi, 153) _OCL_EXT_OP(s_mad_sat, 155) _OCL_EXT_OP(u_mad_sat, 154) _OCL_EXT_OP(s_max, 156) _OCL_EXT_OP(s_min, 158) _OCL_EXT_OP(u_max, 157) _OCL_EXT_OP(u_min, 159) _OCL_EXT_OP(s_mul_hi, 160) _OCL_EXT_OP(rotate, 161) _OCL_EXT_OP(s_sub_sat, 162) _OCL_EXT_OP(u_sub_sat, 163) _OCL_EXT_OP(u_upsample, 164) _OCL_EXT_OP(s_upsample, 165) _OCL_EXT_OP(popcount, 166) _OCL_EXT_OP(s_mad24, 167) _OCL_EXT_OP(u_mad24, 168) _OCL_EXT_OP(s_mul24, 169) _OCL_EXT_OP(u_mul24, 170) // Vector Loads/Stores _OCL_EXT_OP(vloadn, 171) _OCL_EXT_OP(vstoren, 172) _OCL_EXT_OP(vload_half, 173) _OCL_EXT_OP(vload_halfn, 174) _OCL_EXT_OP(vstore_half, 175) _OCL_EXT_OP(vstore_half_r, 176) _OCL_EXT_OP(vstore_halfn, 177) _OCL_EXT_OP(vstore_halfn_r, 178) _OCL_EXT_OP(vloada_halfn, 179) _OCL_EXT_OP(vstorea_halfn, 180) _OCL_EXT_OP(vstorea_halfn_r, 181) // Vector Misc _OCL_EXT_OP(shuffle, 182) _OCL_EXT_OP(shuffle2, 183) _OCL_EXT_OP(printf, 184) _OCL_EXT_OP(prefetch, 185) // Relationals _OCL_EXT_OP(bitselect, 186) _OCL_EXT_OP(select, 187) // more integers _OCL_EXT_OP(u_abs, 201) _OCL_EXT_OP(u_abs_diff, 202) _OCL_EXT_OP(u_mul_hi, 203) _OCL_EXT_OP(u_mad_hi, 204) intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRV.DebugInfo.h000066400000000000000000000025651363533017100270110ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ namespace SPIRVDebugInfo { enum Entrypoints { #define _OCL_EXT_OP(name, num) name = num, #include "SPIRV.DebugInfofuncs.h" #undef _OCL_EXT_OP }; }; // end namespace intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRV.DebugInfofuncs.h000066400000000000000000000044041363533017100300420ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // Debug info ops _OCL_EXT_OP(DebugInfoNone, 0) _OCL_EXT_OP(CompileUnit, 1) _OCL_EXT_OP(TypeBasic, 2) _OCL_EXT_OP(TypePtr, 3) _OCL_EXT_OP(TypeQualifier, 4) _OCL_EXT_OP(TypeArray, 5) _OCL_EXT_OP(TypeVector, 6) _OCL_EXT_OP(TypeDef, 7) _OCL_EXT_OP(TypeFunction, 8) _OCL_EXT_OP(TypeEnum, 9) _OCL_EXT_OP(TypeComposite, 10) _OCL_EXT_OP(TypeMember, 11) _OCL_EXT_OP(TypeInheritance, 12) _OCL_EXT_OP(TypePtrToMember, 13) _OCL_EXT_OP(TypeTemplate, 14) _OCL_EXT_OP(TypeTemplateParameter, 15) _OCL_EXT_OP(TypeTemplateTemplateParameter, 16) _OCL_EXT_OP(TypeTemplateParameterPack, 17) _OCL_EXT_OP(GlobalVariable, 18) _OCL_EXT_OP(FuncDecl, 19) _OCL_EXT_OP(Function, 20) _OCL_EXT_OP(LexicalBlock, 21) _OCL_EXT_OP(LexicalBlockDiscriminator, 22) _OCL_EXT_OP(Scope, 23) _OCL_EXT_OP(NoScope, 24) _OCL_EXT_OP(InlinedAt, 25) _OCL_EXT_OP(LocalVariable, 26) _OCL_EXT_OP(InlinedVariable, 27) _OCL_EXT_OP(DbgDcl, 28) _OCL_EXT_OP(DbgVal, 29) _OCL_EXT_OP(DbgOperation, 30) _OCL_EXT_OP(DbgExpr, 31) _OCL_EXT_OP(MacroDef, 32) _OCL_EXT_OP(MacroUndef, 33) _OCL_EXT_OP(ImportedEntity, 34) _OCL_EXT_OP(Source, 35)intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVAsm.h000066400000000000000000000105671363533017100256120ustar00rootroot00000000000000//===- SPIRVAsm.h - This file declares SPIR-V Inline Assembler Entries --*- C++ //-*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines the inline assembler entries defined in SPIRV spec with op /// codes. /// /// //===----------------------------------------------------------------------===// #ifndef SPIRV_LIBSPIRV_SPIRVASM_H #define SPIRV_LIBSPIRV_SPIRVASM_H #include "SPIRVEntry.h" #include "SPIRVValue.h" #include "SPIRVInstruction.h" #include "Probe.h" #include #include #include #include namespace spv { class SPIRVAsmTargetINTEL : public SPIRVEntry { public: static const SPIRVWord FixedWC = 2; static const Op OC = OpAsmTargetINTEL; // Complete constructor SPIRVAsmTargetINTEL(SPIRVModule *M, SPIRVId TheId, const std::string &TheTarget) : SPIRVEntry(M, FixedWC + getSizeInWords(TheTarget), OC, TheId), Target(TheTarget) { validate(); } // Incomplete constructor SPIRVAsmTargetINTEL() : SPIRVEntry(OC) {} CapVec getRequiredCapability() const override { return getVec(CapabilityAsmINTEL); } const std::string &getTarget() const { return Target; } protected: void validate() const override { SPIRVEntry::validate(); IGC_ASSERT(WordCount > FixedWC); IGC_ASSERT(OpCode == OC); } _SPIRV_DEF_DEC2(Id, Target) std::string Target; }; class SPIRVAsmINTEL : public SPIRVValue { public: static const SPIRVWord FixedWC = 5; static const Op OC = OpAsmINTEL; // Complete constructor SPIRVAsmINTEL(SPIRVModule *M, SPIRVTypeFunction *TheFunctionType, SPIRVId TheId, SPIRVAsmTargetINTEL *TheTarget, const std::string &TheInstructions, const std::string &TheConstraints) : SPIRVValue(M, FixedWC + getSizeInWords(TheInstructions) + getSizeInWords(TheConstraints), OC, TheFunctionType->getReturnType(), TheId), Target(TheTarget), FunctionType(TheFunctionType), Instructions(TheInstructions), Constraints(TheConstraints) { validate(); } // Incomplete constructor SPIRVAsmINTEL() : SPIRVValue(OC) {} CapVec getRequiredCapability() const override { return getVec(CapabilityAsmINTEL); } const std::string &getInstructions() const { return Instructions; } const std::string &getConstraints() const { return Constraints; } SPIRVTypeFunction *getFunctionType() const { return FunctionType; } protected: _SPIRV_DEF_DEC6(Type, Id, FunctionType, Target, Instructions, Constraints) void validate() const override { SPIRVValue::validate(); IGC_ASSERT(WordCount > FixedWC); IGC_ASSERT(OpCode == OC); } SPIRVAsmTargetINTEL *Target; SPIRVTypeFunction *FunctionType; std::string Instructions; std::string Constraints; }; class SPIRVAsmCallINTEL : public SPIRVInstruction { public: static const SPIRVWord FixedWC = 4; static const Op OC = OpAsmCallINTEL; // Complete constructor SPIRVAsmCallINTEL(SPIRVId TheId, SPIRVAsmINTEL *TheAsm, const std::vector &TheArgs, SPIRVBasicBlock *TheBB) : SPIRVInstruction(FixedWC + TheArgs.size(), OC, TheAsm->getType(), TheId, TheBB), Asm(TheAsm), Args(TheArgs) { validate(); } // Incomplete constructor SPIRVAsmCallINTEL() : SPIRVInstruction(OC) {} CapVec getRequiredCapability() const override { return getVec(CapabilityAsmINTEL); } bool isOperandLiteral(unsigned I) const override { return false; } void setWordCount(SPIRVWord TheWordCount) override { SPIRVEntry::setWordCount(TheWordCount); Args.resize(TheWordCount - FixedWC); } const std::vector &getArguments() const { return Args; } SPIRVAsmINTEL *getAsm() const { return Asm; } protected: _SPIRV_DEF_DEC4(Type, Id, Asm, Args) void validate() const override { SPIRVInstruction::validate(); IGC_ASSERT(WordCount >= FixedWC); IGC_ASSERT(OpCode == OC); IGC_ASSERT(getBasicBlock() && "Invalid BB"); IGC_ASSERT(getBasicBlock()->getModule() == Asm->getModule()); } SPIRVAsmINTEL *Asm; std::vector Args; }; } // namespace spv #endif // SPIRV_LIBSPIRV_SPIRVASM_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVBasicBlock.cpp000066400000000000000000000107401363533017100274120ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVBasicBlock.cpp - SPIR-V Basic Block ------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements SPIRV basic block. /// //===----------------------------------------------------------------------===// #include "SPIRVBasicBlock.h" #include "SPIRVInstruction.h" #include "SPIRVFunction.h" #include "Probe.h" using namespace spv; SPIRVBasicBlock::SPIRVBasicBlock(SPIRVId TheId, SPIRVFunction *Func) :SPIRVValue(Func->getModule(), 2, OpLabel, TheId), ParentF(Func) { setAttr(); validate(); } SPIRVDecoder SPIRVBasicBlock::getDecoder(std::istream &IS){ return SPIRVDecoder(IS, *this); } /// Assume I contains valid Id. SPIRVInstruction * SPIRVBasicBlock::addInstruction(SPIRVInstruction *I, const SPIRVInstruction *InsertBefore) { IGC_ASSERT(I && "Invalid instruction"); Module->add(I); I->setParent(this); if (InsertBefore) { auto Pos = find(InsertBefore); // If insertion of a new instruction before the one passed to the function // is illegal, insertion before the returned instruction is guaranteed // to retain correct instruction order in a block if (Pos != InstVec.begin() && isa(*std::prev(Pos))) --Pos; InstVec.insert(Pos, I); } else InstVec.push_back(I); return I; } _SPIRV_IMP_DEC1(SPIRVBasicBlock, Id) void SPIRVBasicBlock::setScope(SPIRVEntry *Scope) { IGC_ASSERT(Scope && Scope->getOpCode() == OpFunction && "Invalid scope"); setParent(static_cast(Scope)); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVBasicBlock.h000066400000000000000000000121431363533017100270560ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVBasicBlock.h - SPIR-V Basic Block --------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines Basic Block class for SPIR-V. /// //===----------------------------------------------------------------------===// #ifndef SPIRVBASICBLOCK_HPP_ #define SPIRVBASICBLOCK_HPP_ #include "SPIRVValue.h" #include #include "Probe.h" namespace spv{ class SPIRVFunction; class SPIRVInstruction; class SPIRVDecoder; class SPIRVBasicBlock: public SPIRVValue { public: SPIRVBasicBlock(SPIRVId TheId, SPIRVFunction *Func); SPIRVBasicBlock():SPIRVValue(OpLabel), ParentF(NULL){ setAttr(); } SPIRVDecoder getDecoder(std::istream &IS); SPIRVFunction *getParent() const { return ParentF;} size_t getNumInst() const { return InstVec.size();} SPIRVInstruction *getInst(size_t I) const { return InstVec[I];} SPIRVInstruction *getPrevious(const SPIRVInstruction *I) const { auto Loc = find(I); if (Loc == InstVec.end() || Loc == InstVec.begin()) return nullptr; return *(--Loc); } SPIRVInstruction *getNext(const SPIRVInstruction *I) const { auto Loc = find(I); if (Loc == InstVec.end()) return nullptr; ++Loc; if (Loc == InstVec.end()) return nullptr; return *Loc; } // Return the last instruction in the BB or nullptr if the BB is empty. const SPIRVInstruction *getTerminateInstr() const { return InstVec.empty() ? nullptr : InstVec.back(); } void setScope(SPIRVEntry *Scope); void setParent(SPIRVFunction *F) { ParentF = F;} SPIRVInstruction * addInstruction(SPIRVInstruction *I, const SPIRVInstruction *InsertBefore = nullptr); void setAttr() { setHasNoType();} _SPIRV_DCL_DEC void validate()const { SPIRVValue::validate(); IGC_ASSERT(ParentF && "Invalid parent function"); } private: SPIRVFunction *ParentF; typedef std::vector SPIRVInstructionVector; SPIRVInstructionVector InstVec; SPIRVInstructionVector::const_iterator find(const SPIRVInstruction *Inst) const { return std::find(InstVec.begin(), InstVec.end(), Inst); } }; typedef SPIRVBasicBlock SPIRVLabel; } #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVBuiltinEnum.h000066400000000000000000000055701363533017100273230ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ _SPIRV_OP(BuiltInPosition, 0) _SPIRV_OP(BuiltInPointSize, 1) _SPIRV_OP(BuiltInClipDistance, 3) _SPIRV_OP(BuiltInCullDistance, 4) _SPIRV_OP(BuiltInVertexId, 5) _SPIRV_OP(BuiltInInstanceId, 6) _SPIRV_OP(BuiltInPrimitiveId, 7) _SPIRV_OP(BuiltInInvocationId, 8) _SPIRV_OP(BuiltInLayer, 9) _SPIRV_OP(BuiltInViewportIndex, 10) _SPIRV_OP(BuiltInTessLevelOuter, 11) _SPIRV_OP(BuiltInTessLevelInner, 12) _SPIRV_OP(BuiltInTessCoord, 13) _SPIRV_OP(BuiltInPatchVertices, 14) _SPIRV_OP(BuiltInFragCoord, 15) _SPIRV_OP(BuiltInPointCoord, 16) _SPIRV_OP(BuiltInFrontFacing, 17) _SPIRV_OP(BuiltInSampleId, 18) _SPIRV_OP(BuiltInSamplePosition, 19) _SPIRV_OP(BuiltInSampleMask, 20) _SPIRV_OP(BuiltInFragColor, 21) _SPIRV_OP(BuiltInFragDepth, 22) _SPIRV_OP(BuiltInHelperInvocation, 23) _SPIRV_OP(BuiltInNumWorkgroups, 24) _SPIRV_OP(BuiltInWorkgroupSize, 25) _SPIRV_OP(BuiltInWorkgroupId, 26) _SPIRV_OP(BuiltInLocalInvocationId, 27) _SPIRV_OP(BuiltInGlobalInvocationId, 28) _SPIRV_OP(BuiltInLocalInvocationIndex, 29) _SPIRV_OP(BuiltInWorkDim, 30) _SPIRV_OP(BuiltInGlobalSize, 31) _SPIRV_OP(BuiltInEnqueuedWorkgroupSize, 32) _SPIRV_OP(BuiltInGlobalOffset, 33) _SPIRV_OP(BuiltInGlobalLinearId, 34) _SPIRV_OP(BuiltInSubgroupSize, 36) _SPIRV_OP(BuiltInSubgroupMaxSize, 37) _SPIRV_OP(BuiltInNumSubgroups, 38) _SPIRV_OP(BuiltInNumEnqueuedSubgroups, 39) _SPIRV_OP(BuiltInSubgroupId, 40) _SPIRV_OP(BuiltInSubgroupLocalInvocationId, 41) _SPIRV_OP(BuiltInVertexIndex, 42) _SPIRV_OP(BuiltInInstanceIndex, 43) // Ballot extension _SPIRV_OP(BuiltInSubgroupEqMaskKHR, 4416) _SPIRV_OP(BuiltInSubgroupGeMaskKHR, 4417) _SPIRV_OP(BuiltInSubgroupGtMaskKHR, 4418) _SPIRV_OP(BuiltInSubgroupLeMaskKHR, 4419) _SPIRV_OP(BuiltInSubgroupLtMaskKHR, 4420) intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVDebug.cpp000066400000000000000000000043231363533017100264440ustar00rootroot00000000000000//===- SPIRVDebug.cpp - SPIR-V Debug Utility ---------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines variables for enabling/disabling SPIR-V debug macro. /// //===----------------------------------------------------------------------===// #include "SPIRVDebug.h" using namespace spv; bool spv::SPIRVDbgEnable = false; bool spv::SPIRVDbgAssertOnError = true; bool spv::SPIRVDbgErrorMsgIncludesSourceInfo = true; intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVDebug.h000066400000000000000000000051241363533017100261110ustar00rootroot00000000000000//===- SPIRVDebug.h - SPIR-V Debug Utility -----------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines Macros and variables for debugging SPIRV. /// //===----------------------------------------------------------------------===// #ifndef SPIRVDEBUG_HPP_ #define SPIRVDEBUG_HPP_ #include namespace spv{ #define _SPIRVDBG #ifdef _SPIRVDBG #define SPIRVDBG(x) //SPIRV DEBUG dumps not implemented // Enable debug output. extern bool SPIRVDbgEnable; // Include source file and line number in error message. extern bool SPIRVDbgErrorMsgIncludesSourceInfo; // Enable assertion on error extern bool SPIRVDbgAssertOnError; // Output stream for SPIRV debug information. inline std::ostream& bildbgs() { return std::cerr; } #else #define SPIRVDBG(x) #endif } #endif /* SPIRVDEBUG_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVDebugInfoExt.h000066400000000000000000001066171363533017100274170ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/// //===----------------------------------------------------------------------===// /// \file /// /// This file defines Debug Info ext instruction class for SPIR-V. /// //===----------------------------------------------------------------------===// #ifndef SPIRVDEBUGINFOEXT_HPP_ #define SPIRVDEBUGINFOEXT_HPP_ #include "SPIRVEntry.h" #include "SPIRVInstruction.h" #include "SPIRVExtInst.h" namespace spv { // SPIRVDebug is shared with common clang's SPIRV emitter namespace SPIRVDebug { const unsigned int DebugInfoVersion = 10000; enum Instruction { DebugInfoNone = 0, CompilationUnit = 1, TypeBasic = 2, TypePointer = 3, TypeQualifier = 4, TypeArray = 5, TypeVector = 6, Typedef = 7, TypeFunction = 8, TypeEnum = 9, TypeComposite = 10, TypeMember = 11, Inheritance = 12, TypePtrToMember = 13, TypeTemplate = 14, TypeTemplateParameter = 15, TypeTemplateParameterPack = 16, TypeTemplateTemplateParameter = 17, GlobalVariable = 18, FunctionDecl = 19, Function = 20, LexicalBlock = 21, LexicalBlockDiscriminator = 22, Scope = 23, NoScope = 24, InlinedAt = 25, LocalVariable = 26, InlinedVariable = 27, Declare = 28, Value = 29, Operation = 30, Expression = 31, MacroDef = 32, MacroUndef = 33, ImportedEntity = 34, Source = 35, InstCount = 36 }; enum Flag { FlagIsPrivate = 1 << 0, FlagIsProtected = 1 << 1, FlagIsPublic = FlagIsPrivate | FlagIsProtected, FlagAccess = FlagIsPublic, FlagIsLocal = 1 << 2, FlagIsDefinition = 1 << 3, FlagIsFwdDecl = 1 << 4, FlagIsArtificial = 1 << 5, FlagIsExplicit = 1 << 6, FlagIsPrototyped = 1 << 7, FlagIsObjectPointer = 1 << 8, FlagIsStaticMember = 1 << 9, FlagIsIndirectVariable = 1 << 10, FlagIsLValueReference = 1 << 11, FlagIsRValueReference = 1 << 12, FlagIsOptimized = 1 << 13, }; enum EncodingTag { Unspecified = 0, Address = 1, Boolean = 2, Float = 3, Signed = 4, SignedChar = 5, Unsigned = 6, UnsignedChar = 7 }; enum CompositeTypeTag { Class = 0, Structure = 1, Union = 2 }; enum TypeQualifierTag { ConstType = 0, VolatileType = 1, RestrictType = 2, AtomicType = 3 }; enum ExpressionOpCode { Deref = 0, Plus = 1, Minus = 2, PlusUconst = 3, BitPiece = 4, Swap = 5, Xderef = 6, StackValue = 7, Constu = 8, Fragment = 9 }; enum ImportedEntityTag { ImportedModule = 0, ImportedDeclaration = 1, }; namespace Operand { namespace CompilationUnit { enum { SPIRVDebugInfoVersionIdx = 0, DWARFVersionIdx = 1, SourceIdx = 2, LanguageIdx = 3, OperandCount = 4 }; } namespace Source { enum { FileIdx = 0, TextIdx = 1, OperandCount = 2 }; } namespace TypeBasic { enum { NameIdx = 0, SizeIdx = 1, EncodingIdx = 2, OperandCount = 3 }; } namespace TypePointer { enum { BaseTypeIdx = 0, StorageClassIdx = 1, FlagsIdx = 2, OperandCount = 3 }; } namespace TypeQualifier { enum { BaseTypeIdx = 0, QualifierIdx = 1, OperandCount = 2 }; } namespace TypeArray { enum { BaseTypeIdx = 0, ComponentCountIdx = 1, MinOperandCount = 2 }; } namespace TypeVector = TypeArray; namespace Typedef { enum { NameIdx = 0, BaseTypeIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, ParentIdx = 5, OperandCount = 6 }; } namespace TypeFunction { enum { FlagsIdx = 0, ReturnTypeIdx = 1, FirstParameterIdx = 2, MinOperandCount = 2 }; } namespace TypeEnum { enum { NameIdx = 0, UnderlyingTypeIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, ParentIdx = 5, SizeIdx = 6, FlagsIdx = 7, FirstEnumeratorIdx = 8, MinOperandCount = 8 }; } namespace TypeComposite { enum { NameIdx = 0, TagIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, ParentIdx = 5, LinkageNameIdx = 6, SizeIdx = 7, FlagsIdx = 8, FirstMemberIdx = 9, MinOperandCount = 9 }; } namespace TypeMember { enum { NameIdx = 0, TypeIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, ParentIdx = 5, OffsetIdx = 6, SizeIdx = 7, FlagsIdx = 8, ValueIdx = 9, MinOperandCount = 9 }; } namespace TypeInheritance { enum { ChildIdx = 0, ParentIdx = 1, OffsetIdx = 2, SizeIdx = 3, FlagsIdx = 4, OperandCount = 5 }; } namespace PtrToMember { enum { MemberTypeIdx = 0, ParentIdx = 1, OperandCount = 2 }; } namespace Template { enum { TargetIdx = 0, FirstParameterIdx = 1, MinOperandCount = 1 }; } namespace TemplateParameter { enum { NameIdx = 0, TypeIdx = 1, ValueIdx = 2, SourceIdx = 3, LineIdx = 4, ColumnIdx = 5, OperandCount = 6 }; } namespace TemplateTemplateParameter { enum { NameIdx = 0, TemplateNameIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, OperandCount = 4 }; } namespace TemplateParameterPack { enum { NameIdx = 0, SourceIdx = 1, LineIdx = 2, ColumnIdx = 3, FirstParameterIdx = 4, MinOperandCount = 4 }; } namespace GlobalVariable { enum { NameIdx = 0, TypeIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, ParentIdx = 5, LinkageNameIdx = 6, VariableIdx = 7, FlagsIdx = 8, StaticMemberDeclarationIdx = 9, MinOperandCount = 9 }; } namespace FunctionDeclaration { enum { NameIdx = 0, TypeIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, ParentIdx = 5, LinkageNameIdx = 6, FlagsIdx = 7, OperandCount = 8 }; } namespace Function { enum { NameIdx = 0, TypeIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, ParentIdx = 5, LinkageNameIdx = 6, FlagsIdx = 7, ScopeLineIdx = 8, FunctionIdIdx = 9, DeclarationIdx = 10, MinOperandCount = 10 }; } namespace LexicalBlock { enum { SourceIdx = 0, LineIdx = 1, ColumnIdx = 2, ParentIdx = 3, NameIdx = 4, MinOperandCount = 4 }; } namespace LexicalBlockDiscriminator { enum { SourceIdx = 0, DiscriminatorIdx = 1, ParentIdx = 2, OperandCount = 3 }; } namespace Scope { enum { ScopeIdx = 0, InlinedAtIdx = 1, MinOperandCount = 1 }; } namespace NoScope { // No operands } namespace InlinedAt { enum { LineIdx = 0, ScopeIdx = 1, InlinedIdx = 2, MinOperandCount = 2 }; } namespace LocalVariable { enum { NameIdx = 0, TypeIdx = 1, SourceIdx = 2, LineIdx = 3, ColumnIdx = 4, ParentIdx = 5, FlagsIdx = 6, ArgNumberIdx = 7, MinOperandCount = 7 }; } namespace InlinedVariable { enum { VariableIdx = 0, InlinedIdx = 1, OperandCount = 2 }; } namespace DebugDeclare { enum { DebugLocalVarIdx = 0, VariableIdx = 1, ExpressionIdx = 2, OperandCount = 3 }; } namespace DebugValue { enum { DebugLocalVarIdx = 0, ValueIdx = 1, ExpressionIdx = 2, FirstIndexOperandIdx = 3, MinOperandCount = 3 }; } namespace Operation { enum { OpCodeIdx = 0 }; static std::map OpCountMap{ { Deref, 1 }, { Plus, 2 }, { Minus, 2 }, { PlusUconst, 2 }, { BitPiece, 3 }, { Swap, 1 }, { Xderef, 1 }, { StackValue, 1 }, { Constu, 2 }, { Fragment, 3 } }; } namespace ImportedEntity { enum { NameIdx = 0, TagIdx = 1, SourceIdx = 3, EntityIdx = 4, LineIdx = 5, ColumnIdx = 6, ParentIdx = 7, OperandCount = 8 }; } } // namespace Operand } // namespace SPIRVDebug // SPIRV Debug info class containers. These classes are light-weight as they // only help interpret a given SPIRVExtInst during SPIRV->LLVM IR translation. class OpDebugInfoBase { public: OpDebugInfoBase(SPIRVExtInst* i) { extInst = i; } bool isOpDebugInfo() { return true; } protected: SPIRVExtInst* extInst = nullptr; template T arg(unsigned int id) { return static_cast(extInst->getArguments()[id]); } SPIRVString* str(SPIRVId id) { auto item = extInst->getModule()->getEntry(arg(id)); if (item->isString()) return static_cast(item); else return nullptr; } uint64_t const_val(SPIRVId id) { auto item = extInst->getModule()->getEntry(arg(id)); if (item->isConstant()) return static_cast(item)->getZExtIntValue(); else return (uint64_t)-1; } unsigned int getNumArgs() { return extInst->getArguments().size(); } }; class OpCompilationUnit : OpDebugInfoBase { public: OpCompilationUnit(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVWord getSPIRVDIVersion() { return arg(SPIRVDebug::Operand::CompilationUnit::SPIRVDebugInfoVersionIdx); } SPIRVWord getDWARFVersion() { return arg(SPIRVDebug::Operand::CompilationUnit::DWARFVersionIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::CompilationUnit::SourceIdx); } SPIRVWord getLang() { return arg(SPIRVDebug::Operand::CompilationUnit::LanguageIdx); } }; class OpDebugLexicalBlock : OpDebugInfoBase { public: OpDebugLexicalBlock(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getResultId() { return extInst->getId(); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::LexicalBlock::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::LexicalBlock::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::LexicalBlock::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::LexicalBlock::ParentIdx); } const bool hasNameSpace() { return getNumArgs() > SPIRVDebug::Operand::LexicalBlock::MinOperandCount; } SPIRVString* getNameSpace() { return str(SPIRVDebug::Operand::LexicalBlock::NameIdx); } }; class OpDebugSubprogram : OpDebugInfoBase { public: OpDebugSubprogram(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::Function::NameIdx); } SPIRVId getType() { return arg(SPIRVDebug::Operand::Function::TypeIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::Function::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::Function::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::Function::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::Function::ParentIdx); } SPIRVString* getLinkage() { return str(SPIRVDebug::Operand::Function::LinkageNameIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::Function::FlagsIdx); } SPIRVWord getScopeLine() { return arg(SPIRVDebug::Operand::Function::ScopeLineIdx); } SPIRVId getSPIRVFunction() { return arg(SPIRVDebug::Operand::Function::FunctionIdIdx); } }; class OpDebugSubroutineType : OpDebugInfoBase { public: OpDebugSubroutineType(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::TypeFunction::FlagsIdx); } SPIRVId getReturnType() { return arg(SPIRVDebug::Operand::TypeFunction::ReturnTypeIdx); } unsigned int getNumParms() { return getNumArgs() - SPIRVDebug::Operand::TypeFunction::FirstParameterIdx; } SPIRVId getParmType(unsigned int i) { return arg(i + SPIRVDebug::Operand::TypeFunction::FirstParameterIdx); } }; class OpDebugDeclare : OpDebugInfoBase { public: OpDebugDeclare(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getResultId() { return extInst->getId(); } SPIRVId getVar() { return arg(SPIRVDebug::Operand::DebugDeclare::DebugLocalVarIdx); } SPIRVId getLocalVar() { return arg(SPIRVDebug::Operand::DebugDeclare::VariableIdx); } SPIRVId getExpression() { return arg(SPIRVDebug::Operand::DebugDeclare::ExpressionIdx); } }; class OpDebugValue : OpDebugInfoBase { public: OpDebugValue(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getResultId() { return extInst->getId(); } SPIRVId getVar() { return arg(SPIRVDebug::Operand::DebugValue::DebugLocalVarIdx); } SPIRVId getValueVar() { return arg(SPIRVDebug::Operand::DebugValue::ValueIdx); } SPIRVId getExpression() { return arg(SPIRVDebug::Operand::DebugValue::ExpressionIdx); } SPIRVId getIndex(unsigned int i) { return arg(SPIRVDebug::Operand::DebugValue::FirstIndexOperandIdx + i); } }; class OpDebugLocalVar : OpDebugInfoBase { public: bool isParamVar() { return getNumArgs() > SPIRVDebug::Operand::LocalVariable::ArgNumberIdx; } OpDebugLocalVar(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getResultId() { return extInst->getId(); } SPIRVId getName() { return arg(SPIRVDebug::Operand::LocalVariable::NameIdx); } SPIRVId getType() { return arg(SPIRVDebug::Operand::LocalVariable::TypeIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::LocalVariable::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::LocalVariable::LineIdx); } SPIRVWord getCol() { return arg(SPIRVDebug::Operand::LocalVariable::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::LocalVariable::ParentIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::LocalVariable::FlagsIdx); } SPIRVWord getArgNo() { return arg(SPIRVDebug::Operand::LocalVariable::ArgNumberIdx); } }; class OpDebugInlinedLocalVar : OpDebugInfoBase { public: OpDebugInlinedLocalVar(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getVar() { return arg(SPIRVDebug::Operand::InlinedVariable::VariableIdx); } SPIRVId getInlinedAt() { return arg(SPIRVDebug::Operand::InlinedVariable::InlinedIdx); } }; class OpDebugTypeBasic : OpDebugInfoBase { public: OpDebugTypeBasic(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::TypeBasic::NameIdx); } uint64_t getSize() { return const_val(SPIRVDebug::Operand::TypeBasic::SizeIdx); } SPIRVDebug::EncodingTag getEncoding() { return arg(SPIRVDebug::Operand::TypeBasic::EncodingIdx); } }; class OpDebugPtrType : OpDebugInfoBase { public: OpDebugPtrType(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getBaseType() { return arg(SPIRVDebug::Operand::TypePointer::BaseTypeIdx); } SPIRVWord getStorageClass() { return arg(SPIRVDebug::Operand::TypePointer::StorageClassIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::TypePointer::FlagsIdx); } }; class OpDebugTypeQualifier : OpDebugInfoBase { public: OpDebugTypeQualifier(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getBaseType() { return arg(SPIRVDebug::Operand::TypeQualifier::BaseTypeIdx); } enum TypeQualifier { qual_const = 0, qual_volatile = 1, qual_restrict = 2 }; TypeQualifier getQualifier() { return arg(SPIRVDebug::Operand::TypeQualifier::QualifierIdx); } }; class OpDebugTypeArray : OpDebugInfoBase { public: OpDebugTypeArray(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getBaseType() { return arg(SPIRVDebug::Operand::TypeArray::BaseTypeIdx); } SPIRVWord getNumDims() { return (getNumArgs() - SPIRVDebug::Operand::TypeArray::ComponentCountIdx); } SPIRVId getComponentCount(unsigned int i) { return arg(i + SPIRVDebug::Operand::TypeArray::ComponentCountIdx); } }; class OpDebugTypeVector : OpDebugInfoBase { public: OpDebugTypeVector(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getBaseType() { return arg(SPIRVDebug::Operand::TypeVector::BaseTypeIdx); } SPIRVWord getNumComponents() { return arg(SPIRVDebug::Operand::TypeVector::ComponentCountIdx); } }; class OpDebugTypeDef : OpDebugInfoBase { public: OpDebugTypeDef(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::Typedef::NameIdx); } SPIRVId getBaseType() { return arg(SPIRVDebug::Operand::Typedef::BaseTypeIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::Typedef::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::Typedef::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::Typedef::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::Typedef::ParentIdx); } }; class OpDebugTypeEnum : OpDebugInfoBase { public: OpDebugTypeEnum(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::TypeEnum::NameIdx); } SPIRVId getType() { return arg(SPIRVDebug::Operand::TypeEnum::UnderlyingTypeIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::TypeEnum::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::TypeEnum::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::TypeEnum::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::TypeEnum::ParentIdx); } uint64_t getSize() { return const_val(SPIRVDebug::Operand::TypeEnum::SizeIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::TypeEnum::FlagsIdx); } std::pair getItem(unsigned int idx) { return std::make_pair(str((idx * 2) + SPIRVDebug::Operand::TypeEnum::FirstEnumeratorIdx+1), const_val((idx * 2) + SPIRVDebug::Operand::TypeEnum::FirstEnumeratorIdx)); } unsigned int getNumItems() { return (getNumArgs() - SPIRVDebug::Operand::TypeEnum::FirstEnumeratorIdx)/2; } }; class OpDebugTypeComposite : OpDebugInfoBase { public: OpDebugTypeComposite(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::TypeComposite::NameIdx); } SPIRVWord getTag() { return arg(SPIRVDebug::Operand::TypeComposite::TagIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::TypeComposite::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::TypeComposite::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::TypeComposite::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::TypeComposite::ParentIdx); } SPIRVString* getLinkageName() { return str(SPIRVDebug::Operand::TypeComposite::LinkageNameIdx); } uint64_t getSize() { return const_val(SPIRVDebug::Operand::TypeComposite::SizeIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::TypeComposite::FlagsIdx); } unsigned int getNumItems() { return (getNumArgs() - SPIRVDebug::Operand::TypeComposite::FirstMemberIdx); } SPIRVId getItem(unsigned int i) { return arg(i + SPIRVDebug::Operand::TypeComposite::FirstMemberIdx); } }; class OpDebugTypeMember : OpDebugInfoBase { public: OpDebugTypeMember(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::TypeMember::NameIdx); } SPIRVId getType() { return arg(SPIRVDebug::Operand::TypeMember::TypeIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::TypeMember::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::TypeMember::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::TypeMember::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::TypeMember::ParentIdx); } uint64_t getOffset() { return const_val(SPIRVDebug::Operand::TypeMember::OffsetIdx); } uint64_t getSize() { return const_val(SPIRVDebug::Operand::TypeMember::SizeIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::TypeMember::FlagsIdx); } uint64_t getInitConst() { return const_val(SPIRVDebug::Operand::TypeMember::ValueIdx); } bool hasInitConst() { return getNumArgs() > SPIRVDebug::Operand::TypeMember::MinOperandCount; } }; class OpDebugTypeInheritance : OpDebugInfoBase { public: OpDebugTypeInheritance(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getChild() { return arg(SPIRVDebug::Operand::TypeInheritance::ChildIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::TypeInheritance::ParentIdx); } uint64_t getOffset() { return const_val(SPIRVDebug::Operand::TypeInheritance::OffsetIdx); } uint64_t getSize() { return const_val(SPIRVDebug::Operand::TypeInheritance::SizeIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::TypeInheritance::FlagsIdx); } }; class OpDebugPtrToMember : OpDebugInfoBase { public: OpDebugPtrToMember(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getType() { return arg(SPIRVDebug::Operand::PtrToMember::MemberTypeIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::PtrToMember::ParentIdx); } }; class OpDebugGlobalVar : OpDebugInfoBase { public: OpDebugGlobalVar(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::GlobalVariable::NameIdx); } SPIRVId getType() { return arg(SPIRVDebug::Operand::GlobalVariable::TypeIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::GlobalVariable::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::GlobalVariable::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::GlobalVariable::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::GlobalVariable::ParentIdx); } SPIRVString* getLinkageName() { return str(SPIRVDebug::Operand::GlobalVariable::LinkageNameIdx); } SPIRVId getVariable() { return arg(SPIRVDebug::Operand::GlobalVariable::VariableIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::GlobalVariable::FlagsIdx); } bool hasStaticDecl() { return getNumArgs() > SPIRVDebug::Operand::GlobalVariable::MinOperandCount; } SPIRVId getStaticMemberDecl() { return arg(SPIRVDebug::Operand::GlobalVariable::StaticMemberDeclarationIdx); } }; class OpDebugFuncDecl : OpDebugInfoBase { public: OpDebugFuncDecl(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::FunctionDeclaration::NameIdx); } SPIRVId getType() { return arg(SPIRVDebug::Operand::FunctionDeclaration::TypeIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::FunctionDeclaration::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::FunctionDeclaration::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::FunctionDeclaration::ColumnIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::FunctionDeclaration::ParentIdx); } SPIRVString* getLinkageName() { return str(SPIRVDebug::Operand::FunctionDeclaration::LinkageNameIdx); } SPIRVWord getFlags() { return arg(SPIRVDebug::Operand::FunctionDeclaration::FlagsIdx); } }; class OpDebugLexicalBlkDiscriminator : OpDebugInfoBase { public: OpDebugLexicalBlkDiscriminator(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getSource() { return arg(SPIRVDebug::Operand::LexicalBlockDiscriminator::SourceIdx); } SPIRVWord getDiscriminator() { return arg(SPIRVDebug::Operand::LexicalBlockDiscriminator::DiscriminatorIdx); } SPIRVId getParent() { return arg(SPIRVDebug::Operand::LexicalBlockDiscriminator::ParentIdx); } }; class OpDebugScope : OpDebugInfoBase { public: OpDebugScope(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getScope() { return arg(SPIRVDebug::Operand::Scope::ScopeIdx); } bool hasInlinedAt() { return getNumArgs() > SPIRVDebug::Operand::Scope::MinOperandCount; } SPIRVId getInlinedAt() { return arg(SPIRVDebug::Operand::Scope::InlinedAtIdx); } }; class OpDebugSource : OpDebugInfoBase { public: OpDebugSource(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getFileStr() { return str(SPIRVDebug::Operand::Source::FileIdx); } }; class OpDebugInlinedAt : OpDebugInfoBase { public: OpDebugInlinedAt(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVWord getLine() { return arg(SPIRVDebug::Operand::InlinedAt::LineIdx); } SPIRVId getScope() { return arg(SPIRVDebug::Operand::InlinedAt::ScopeIdx); } bool inlinedAtPresent() { return getNumArgs() > SPIRVDebug::Operand::InlinedAt::MinOperandCount; } SPIRVId getInlinedAt() { return arg(SPIRVDebug::Operand::InlinedAt::InlinedIdx); } }; class OpDebugTypeTemplate : OpDebugInfoBase { public: OpDebugTypeTemplate(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVId getTarget() { return arg(SPIRVDebug::Operand::Template::TargetIdx); } SPIRVId getParm(unsigned int i) { return arg(i+SPIRVDebug::Operand::Template::FirstParameterIdx); } unsigned int getNumParms() { return (getNumArgs() - SPIRVDebug::Operand::Template::FirstParameterIdx); } }; class OpDebugTypeTemplateParm : OpDebugInfoBase { public: OpDebugTypeTemplateParm(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::TemplateParameter::NameIdx); } SPIRVId getActualType() { return arg(SPIRVDebug::Operand::TemplateParameter::TypeIdx); } bool hasValue() { return const_val(SPIRVDebug::Operand::TemplateParameter::ValueIdx) != (uint64_t)-1; } uint64_t getValue() { return const_val(SPIRVDebug::Operand::TemplateParameter::ValueIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::TemplateParameter::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::TemplateParameter::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::TemplateParameter::ColumnIdx); } }; class OpDebugTypeTemplateParmPack : OpDebugInfoBase { public: OpDebugTypeTemplateParmPack(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::TemplateParameterPack::NameIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::TemplateParameterPack::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::TemplateParameterPack::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::TemplateParameterPack::ColumnIdx); } SPIRVId getParm(unsigned int i) { return arg(i + SPIRVDebug::Operand::TemplateParameterPack::FirstParameterIdx); } unsigned int getNumParms() { return (getNumArgs() - SPIRVDebug::Operand::TemplateParameterPack::FirstParameterIdx); } }; class OpDebugTypeTemplateTemplateParm : OpDebugInfoBase { public: OpDebugTypeTemplateTemplateParm(SPIRVExtInst* extInst) : OpDebugInfoBase(extInst) {} SPIRVString* getName() { return str(SPIRVDebug::Operand::TemplateTemplateParameter::NameIdx); } SPIRVString* getTemplateName() { return str(SPIRVDebug::Operand::TemplateTemplateParameter::TemplateNameIdx); } SPIRVId getSource() { return arg(SPIRVDebug::Operand::TemplateTemplateParameter::SourceIdx); } SPIRVWord getLine() { return arg(SPIRVDebug::Operand::TemplateTemplateParameter::LineIdx); } SPIRVWord getColumn() { return arg(SPIRVDebug::Operand::TemplateTemplateParameter::ColumnIdx); } }; } #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVDecorate.cpp000066400000000000000000000162121363533017100271440ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVDecorate.cpp -SPIR-V Decorations ---------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements SPIR-V decorations. /// //===----------------------------------------------------------------------===// #include "SPIRVDecorate.h" #include "SPIRVValue.h" #include "Probe.h" namespace spv{ SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec, SPIRVEntry *TheTarget) :SPIRVAnnotationGeneric(TheTarget, WC, OC), Dec(TheDec), Owner(nullptr){ validate(); } SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V) :SPIRVAnnotationGeneric(TheTarget, WC, OC), Dec(TheDec), Owner(nullptr){ Literals.push_back(V); validate(); } SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC) :SPIRVAnnotationGeneric(OC), Dec(DecorationRelaxedPrecision), Owner(nullptr){ } Decoration SPIRVDecorateGeneric::getDecorateKind()const { return Dec; } SPIRVWord SPIRVDecorateGeneric::getLiteral(size_t i) const { IGC_ASSERT_EXIT(i <= Literals.size() && "Out of bounds"); return Literals[i]; } std::vector SPIRVDecorateGeneric::getVecLiteral() const { return Literals; } size_t SPIRVDecorateGeneric::getLiteralCount() const { return Literals.size(); } void SPIRVDecorate::setWordCount(SPIRVWord Count){ WordCount = Count; Literals.resize(WordCount - FixedWC); } void SPIRVDecorate::decode(std::istream &I) { getDecoder(I) >> Target >> Dec; auto currLoc = I.tellg(); getDecoder(I) >> Literals; auto *target = getOrCreateTarget(); if (Dec == DecorationLinkageAttributes) { I.seekg(currLoc); std::string funcName; getDecoder(I) >> funcName; target->setName(funcName); } target->addDecorate(this); } void SPIRVMemberDecorate::setWordCount(SPIRVWord Count){ WordCount = Count; Literals.resize(WordCount - FixedWC); } void SPIRVMemberDecorate::decode(std::istream &I){ getDecoder(I) >> Target >> MemberNumber >> Dec >> Literals; getOrCreateTarget()->addMemberDecorate(this); } void SPIRVDecorationGroup::decode(std::istream &I){ getDecoder(I) >> Id; Module->addDecorationGroup(this); } void SPIRVGroupDecorateGeneric::decode(std::istream &I){ getDecoder(I) >> DecorationGroup >> Targets; Module->addGroupDecorateGeneric(this); } void SPIRVGroupDecorate::decorateTargets() { for(auto &I:Targets) { auto Target = getOrCreate(I); for (auto &Dec:DecorationGroup->getDecorations()) { IGC_ASSERT(Dec->isDecorate()); Target->addDecorate(static_cast(Dec)); } } } void SPIRVGroupMemberDecorate::decorateTargets() { for(auto &I:Targets) { auto Target = getOrCreate(I); for (auto &Dec:DecorationGroup->getDecorations()) { IGC_ASSERT(Dec->isMemberDecorate()); Target->addMemberDecorate(static_cast(Dec)); } } } bool SPIRVDecorateGeneric::Comparator::operator()(const SPIRVDecorateGeneric *A, const SPIRVDecorateGeneric *B) const{ auto Action = [=](){ if (A->getOpCode() < B->getOpCode()) return true; if (A->getOpCode() > B->getOpCode()) return false; if (A->getDecorateKind() < B->getDecorateKind()) return true; if (A->getDecorateKind() > B->getDecorateKind()) return false; if (A->getLiteralCount() < B->getLiteralCount()) return true; if (A->getLiteralCount() > B->getLiteralCount()) return false; for (size_t I = 0, E = A->getLiteralCount(); I != E; ++I) { auto EA = A->getLiteral(I); auto EB = B->getLiteral(I); if (EA < EB) return true; if (EA > EB) return false; } return false; }; auto Res = Action(); return Res; } bool operator==(const SPIRVDecorateGeneric &A, const SPIRVDecorateGeneric &B) { if (A.getTargetId() != B.getTargetId()) return false; if (A.getOpCode() != B.getOpCode()) return false; if (A.getDecorateKind() != B.getDecorateKind()) return false; if (A.getLiteralCount() != B.getLiteralCount()) return false; for (size_t I = 0, E = A.getLiteralCount(); I != E; ++I) { auto EA = A.getLiteral(I); auto EB = B.getLiteral(I); if (EA != EB) return false; } return true; } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVDecorate.h000066400000000000000000000222421363533017100266110ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVDecorate.h - SPIR-V Decorations ----------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines SPIR-V decorations. /// //===----------------------------------------------------------------------===// #ifndef SPIRVDECORATE_HPP_ #define SPIRVDECORATE_HPP_ #include "SPIRVEntry.h" #include "Probe.h" namespace spv{ class SPIRVDecorationGroup; class SPIRVDecorateGeneric:public SPIRVAnnotationGeneric{ public: // Complete constructor for decorations without literals SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec, SPIRVEntry *TheTarget); // Complete constructor for decorations with one word literal SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V); // Incomplete constructor SPIRVDecorateGeneric(Op OC); SPIRVWord getLiteral(size_t) const; std::vector getVecLiteral() const; Decoration getDecorateKind() const; size_t getLiteralCount() const; /// Compare for kind and literal only. struct Comparator { bool operator()(const SPIRVDecorateGeneric *A, const SPIRVDecorateGeneric *B) const; }; /// Compare kind, literals and target. friend bool operator==(const SPIRVDecorateGeneric &A, const SPIRVDecorateGeneric &B); SPIRVDecorationGroup* getOwner() const { return Owner; } void setOwner(SPIRVDecorationGroup* owner) { Owner = owner; } protected: Decoration Dec; std::vector Literals; SPIRVDecorationGroup *Owner; // Owning decorate group }; class SPIRVDecorateSet: public std::multiset { public: typedef std::multiset BaseType; iterator insert(const value_type& Dec) { auto ER = BaseType::equal_range(Dec); for (auto I = ER.first, E = ER.second; I != E; ++I) { SPIRVDBG(bildbgs() << "[compare decorate] " << *Dec << " vs " << **I << " : "); if (**I == *Dec) return I; SPIRVDBG(bildbgs() << " diff\n"); } SPIRVDBG(bildbgs() << "[add decorate] " << *Dec << '\n'); return BaseType::insert(Dec); } }; class SPIRVDecorate:public SPIRVDecorateGeneric{ public: static const Op OC = OpDecorate; static const SPIRVWord FixedWC = 3; // Complete constructor for decorations without literals SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget) :SPIRVDecorateGeneric(OC, 3, TheDec, TheTarget){} // Complete constructor for decorations with one word literal SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V) :SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget, V){} // Incomplete constructor SPIRVDecorate():SPIRVDecorateGeneric(OC){} _SPIRV_DCL_DEC void setWordCount(SPIRVWord); }; class SPIRVMemberDecorate:public SPIRVDecorateGeneric{ public: static const Op OC = OpMemberDecorate; static const SPIRVWord FixedWC = 4; // Complete constructor for decorations without literals SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member, SPIRVEntry *TheTarget) :SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget), MemberNumber(Member){} // Complete constructor for decorations with one word literal SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member, SPIRVEntry *TheTarget, SPIRVWord V) :SPIRVDecorateGeneric(OC, 5, TheDec, TheTarget, V), MemberNumber(Member){} // Incomplete constructor SPIRVMemberDecorate():SPIRVDecorateGeneric(OC), MemberNumber(SPIRVWORD_MAX){} SPIRVWord getMemberNumber() const { return MemberNumber;} std::pair getPair() const { return std::make_pair(MemberNumber, Dec); } _SPIRV_DCL_DEC void setWordCount(SPIRVWord); protected: SPIRVWord MemberNumber; }; class SPIRVDecorationGroup:public SPIRVEntry{ public: static const Op OC = OpDecorationGroup; static const SPIRVWord WC = 2; // Complete constructor. Does not populate Decorations. SPIRVDecorationGroup(SPIRVModule *TheModule, SPIRVId TheId) :SPIRVEntry(TheModule, WC, OC, TheId){ validate(); }; // Incomplete constructor SPIRVDecorationGroup():SPIRVEntry(OC){} _SPIRV_DCL_DEC // Move the given decorates to the decoration group void takeDecorates(SPIRVDecorateSet &Decs) { Decorations = std::move(Decs); for (auto &I:Decorations) const_cast(I)->setOwner(this); Decs.clear(); } SPIRVDecorateSet& getDecorations() { return Decorations; } protected: SPIRVDecorateSet Decorations; void validate()const { IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == WC); } }; class SPIRVGroupDecorateGeneric:public SPIRVEntryNoIdGeneric{ public: static const SPIRVWord FixedWC = 2; // Complete constructor SPIRVGroupDecorateGeneric(Op OC, SPIRVDecorationGroup *TheGroup, const std::vector &TheTargets) :SPIRVEntryNoIdGeneric(TheGroup->getModule(), FixedWC + TheTargets.size(), OC), DecorationGroup(TheGroup), Targets(TheTargets){ } // Incomplete constructor SPIRVGroupDecorateGeneric(Op OC) :SPIRVEntryNoIdGeneric(OC), DecorationGroup(nullptr){} void setWordCount(SPIRVWord WC) { SPIRVEntryNoIdGeneric::setWordCount(WC); Targets.resize(WC - FixedWC); } virtual void decorateTargets() = 0; _SPIRV_DCL_DEC protected: SPIRVDecorationGroup *DecorationGroup; std::vector Targets; }; class SPIRVGroupDecorate:public SPIRVGroupDecorateGeneric{ public: static const Op OC = OpGroupDecorate; // Complete constructor SPIRVGroupDecorate(SPIRVDecorationGroup *TheGroup, const std::vector &TheTargets) :SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){} // Incomplete constructor SPIRVGroupDecorate() :SPIRVGroupDecorateGeneric(OC){} virtual void decorateTargets(); }; class SPIRVGroupMemberDecorate:public SPIRVGroupDecorateGeneric{ public: static const Op OC = OpGroupMemberDecorate; // Complete constructor SPIRVGroupMemberDecorate(SPIRVDecorationGroup *TheGroup, const std::vector &TheTargets) :SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){} // Incomplete constructor SPIRVGroupMemberDecorate() :SPIRVGroupDecorateGeneric(OC){} virtual void decorateTargets(); }; } #endif /* SPIRVDECORATE_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVEntry.cpp000066400000000000000000000364541363533017100265310ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVEntry.cpp - Base Class for SPIR-V Entities -----------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements base class for SPIR-V entities. /// //===----------------------------------------------------------------------===// #include "SPIRVEntry.h" #include "SPIRVFunction.h" #include "SPIRVInstruction.h" #include "SPIRVAsm.h" #include "Probe.h" namespace spv{ template SPIRVEntry* create() { return new T(); } SPIRVEntry * SPIRVEntry::create(Op OpCode) { switch (OpCode) { #define _SPIRV_OP(x,...) case Op##x: return spv::create(); #include "SPIRVOpCodeEnum.h" #undef _SPIRV_OP default: IGC_ASSERT_EXIT(0 && "No factory the OpCode "); break; } return 0; } SPIRVErrorLog & SPIRVEntry::getErrorLog()const { return Module->getErrorLog(); } bool SPIRVEntry::exist(SPIRVId TheId)const { return Module->exist(TheId); } SPIRVEntry * SPIRVEntry::getOrCreate(SPIRVId TheId)const { SPIRVEntry *Entry = nullptr; bool Found = Module->exist(TheId, &Entry); if (!Found) return Module->addForward(TheId, nullptr); return Entry; } SPIRVValue * SPIRVEntry::getValue(SPIRVId TheId)const { return get(TheId); } SPIRVType * SPIRVEntry::getValueType(SPIRVId TheId)const { return get(TheId)->getType(); } SPIRVDecoder SPIRVEntry::getDecoder(std::istream& I){ return SPIRVDecoder(I, *Module); } void SPIRVEntry::setWordCount(SPIRVWord TheWordCount){ WordCount = TheWordCount; } void SPIRVEntry::setName(const std::string& TheName) { Name = TheName; } void SPIRVEntry::setModule(SPIRVModule *TheModule) { IGC_ASSERT(TheModule && "Invalid module"); if (TheModule == Module) return; IGC_ASSERT(Module == NULL && "Cannot change owner of entry"); Module = TheModule; } // Read words from SPIRV binary and create members for SPIRVEntry. // The word count and op code has already been read before calling this // function for creating the SPIRVEntry. Therefore the input stream only // contains the remaining part of the words for the SPIRVEntry. void SPIRVEntry::decode(std::istream &I) { IGC_ASSERT_EXIT(0 && "Not implemented"); } std::vector SPIRVEntry::getValues(const std::vector& IdVec)const { std::vector ValueVec; for (auto i:IdVec) ValueVec.push_back(getValue(i)); return ValueVec; } std::vector SPIRVEntry::getValueTypes(const std::vector& IdVec)const { std::vector TypeVec; for (auto i:IdVec) TypeVec.push_back(getValue(i)->getType()); return TypeVec; } std::vector SPIRVEntry::getIds(const std::vector ValueVec)const { std::vector IdVec; for (auto i:ValueVec) IdVec.push_back(i->getId()); return IdVec; } SPIRVEntry * SPIRVEntry::getEntry(SPIRVId TheId) const { return Module->getEntry(TheId); } void SPIRVEntry::validateFunctionControlMask(SPIRVWord TheFCtlMask) const { SPIRVCK(TheFCtlMask <= (unsigned)SPIRVFunctionControlMaskKind::FunctionControlMaskMax, InvalidFunctionControlMask, ""); } void SPIRVEntry::validateValues(const std::vector &Ids)const { for (auto I:Ids) getValue(I)->validate(); } void SPIRVEntry::validateBuiltin(SPIRVWord TheSet, SPIRVWord Index)const { IGC_ASSERT(TheSet != SPIRVWORD_MAX && Index != SPIRVWORD_MAX && "Invalid builtin"); } void SPIRVEntry::addDecorate(const SPIRVDecorate *Dec){ Decorates.insert(std::make_pair(Dec->getDecorateKind(), Dec)); Module->addDecorate(Dec); } void SPIRVEntry::addDecorate(Decoration Kind) { addDecorate(new SPIRVDecorate(Kind, this)); } void SPIRVEntry::addDecorate(Decoration Kind, SPIRVWord Literal) { addDecorate(new SPIRVDecorate(Kind, this, Literal)); } void SPIRVEntry::eraseDecorate(Decoration Dec){ Decorates.erase(Dec); } void SPIRVEntry::takeDecorates(SPIRVEntry *E){ Decorates = std::move(E->Decorates); } void SPIRVEntry::setLine(SPIRVLine *L){ Line = L; } void SPIRVEntry::setDIScope(SPIRVExtInst* I) { diScope = I; } SPIRVExtInst* SPIRVEntry::getDIScope() { return diScope; } void SPIRVEntry::takeLine(SPIRVEntry *E){ Line = E->Line; if (Line == nullptr) return; E->Line = nullptr; } void SPIRVEntry::addMemberDecorate(const SPIRVMemberDecorate *Dec){ IGC_ASSERT(canHaveMemberDecorates() && MemberDecorates.find(Dec->getPair()) == MemberDecorates.end()); MemberDecorates[Dec->getPair()] = Dec; Module->addDecorate(Dec); } void SPIRVEntry::addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind) { addMemberDecorate(new SPIRVMemberDecorate(Kind, MemberNumber, this)); } void SPIRVEntry::addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind, SPIRVWord Literal) { addMemberDecorate(new SPIRVMemberDecorate(Kind, MemberNumber, this, Literal)); } void SPIRVEntry::eraseMemberDecorate(SPIRVWord MemberNumber, Decoration Dec){ MemberDecorates.erase(std::make_pair(MemberNumber, Dec)); } void SPIRVEntry::takeMemberDecorates(SPIRVEntry *E){ MemberDecorates = std::move(E->MemberDecorates); } void SPIRVEntry::takeAnnotations(SPIRVForward *E){ Module->setName(this, E->getName()); takeDecorates(E); takeMemberDecorates(E); takeLine(E); if (OpCode == OpFunction) static_cast(this)->takeExecutionModes(E); } // Check if an entry has Kind of decoration and get the literal of the // first decoration of such kind at Index. bool SPIRVEntry::hasDecorate(Decoration Kind, size_t Index, SPIRVWord *Result)const { DecorateMapType::const_iterator Loc = Decorates.find(Kind); if (Loc == Decorates.end()) return false; if (Result) { *Result = Loc->second->getLiteral(Index); } return true; } // Get literals of all decorations of Kind at Index. std::set SPIRVEntry::getDecorate(Decoration Kind, size_t Index) const { auto Range = Decorates.equal_range(Kind); std::set Value; for (auto I = Range.first, E = Range.second; I != E; ++I) { IGC_ASSERT(Index < I->second->getLiteralCount() && "Invalid index"); Value.insert(I->second->getLiteral(Index)); } return Value; } std::vector SPIRVEntry::getDecorationStringLiteral(Decoration Kind) const { auto Loc = Decorates.equal_range(Kind); if (Loc.first == Decorates.end()) return {}; std::vector DecorationStrings; for (auto it = Loc.first; it != Loc.second; ++it) { auto v = getVecString(it->second->getVecLiteral()); DecorationStrings.insert(DecorationStrings.end(), v.begin(), v.end()); } return DecorationStrings; } bool SPIRVEntry::hasLinkageType() const { return OpCode == OpFunction || OpCode == OpVariable; } SPIRVLinkageTypeKind SPIRVEntry::getLinkageType() const { auto hasLinkageAttr = [&](SPIRVWord *Result) { auto Loc = Decorates.find(DecorationLinkageAttributes); if (Loc == Decorates.end()) return false; if (Result) { auto *Dec = Loc->second; // Linkage Attributes has an arbitrary width string to start. The // last Word is the linkage type. *Result = Dec->getLiteral(Dec->getLiteralCount() - 1); } return true; }; IGC_ASSERT(hasLinkageType()); SPIRVWord LT = SPIRVLinkageTypeKind::LinkageTypeCount; if (!hasLinkageAttr(<)) return SPIRVLinkageTypeKind::LinkageTypeInternal; return static_cast(LT); } void SPIRVEntry::setLinkageType(SPIRVLinkageTypeKind LT) { IGC_ASSERT(isValid(LT)); IGC_ASSERT(hasLinkageType()); addDecorate(new SPIRVDecorate(DecorationLinkageAttributes, this, LT)); } std::istream & operator>>(std::istream &I, SPIRVEntry &E) { E.decode(I); return I; } SPIRVEntryPoint::SPIRVEntryPoint(SPIRVModule *TheModule, SPIRVExecutionModelKind TheExecModel, SPIRVId TheId, const std::string &TheName) :SPIRVAnnotation(TheModule->get(TheId), getSizeInWords(TheName) + 3), ExecModel(TheExecModel), Name(TheName){ } void SPIRVEntryPoint::decode(std::istream &I) { getDecoder(I) >> ExecModel >> Target >> Name; Module->setName(getOrCreateTarget(), Name); Module->addEntryPoint(ExecModel, Target); } void SPIRVExecutionMode::decode(std::istream &I) { getDecoder(I) >> Target >> ExecMode; switch(ExecMode) { case SPIRVExecutionModeKind::ExecutionModeLocalSize: case SPIRVExecutionModeKind::ExecutionModeLocalSizeHint: WordLiterals.resize(3); break; case SPIRVExecutionModeKind::ExecutionModeInvocations: case SPIRVExecutionModeKind::ExecutionModeOutputVertices: case SPIRVExecutionModeKind::ExecutionModeVecTypeHint: case SPIRVExecutionModeKind::ExecutionModeSubgroupSize: case SPIRVExecutionModeKind::ExecutionModeSubgroupsPerWorkgroup: WordLiterals.resize(1); break; default: // Do nothing. Keep this to avoid VS2013 warning. break; } getDecoder(I) >> WordLiterals; getOrCreateTarget()->addExecutionMode(this); } SPIRVForward * SPIRVAnnotationGeneric::getOrCreateTarget()const { SPIRVEntry *Entry = nullptr; bool Found = Module->exist(Target, &Entry); IGC_ASSERT((!Found || Entry->getOpCode() == OpForward) && "Annotations only allowed on forward"); if (!Found) Entry = Module->addForward(Target, nullptr); return static_cast(Entry); } SPIRVName::SPIRVName(const SPIRVEntry *TheTarget, const std::string& TheStr) :SPIRVAnnotation(TheTarget, getSizeInWords(TheStr) + 2), Str(TheStr){ } void SPIRVName::decode(std::istream &I) { getDecoder(I) >> Target >> Str; Module->setName(getOrCreateTarget(), Str); } void SPIRVName::validate() const { IGC_ASSERT(WordCount == getSizeInWords(Str) + 2 && "Incorrect word count"); } _SPIRV_IMP_DEC2(SPIRVString, Id, Str) _SPIRV_IMP_DEC3(SPIRVMemberName, Target, MemberNumber, Str) void SPIRVLine::decode(std::istream &I) { getDecoder(I) >> FileName >> Line >> Column; } void SPIRVLine::validate() const { IGC_ASSERT(OpCode == OpLine); IGC_ASSERT(WordCount == 5); IGC_ASSERT(get(FileName)->getOpCode() == OpString); IGC_ASSERT(Line != SPIRVWORD_MAX); IGC_ASSERT(Column != SPIRVWORD_MAX); } void SPIRVNoLine::decode(std::istream &I) { } void SPIRVNoLine::validate() const { IGC_ASSERT(OpCode == OpNoLine); IGC_ASSERT(WordCount == 1); } void SPIRVMemberName::validate() const { IGC_ASSERT(OpCode == OpMemberName); IGC_ASSERT(WordCount == getSizeInWords(Str) + FixedWC); IGC_ASSERT(get(Target)->getOpCode() == OpTypeStruct); IGC_ASSERT(MemberNumber < get(Target)->getStructMemberCount()); } SPIRVExtInstImport::SPIRVExtInstImport(SPIRVModule *TheModule, SPIRVId TheId, const std::string &TheStr): SPIRVEntry(TheModule, 2 + getSizeInWords(TheStr), OC, TheId), Str(TheStr){ validate(); } void SPIRVExtInstImport::decode(std::istream &I) { getDecoder(I) >> Id >> Str; Module->importBuiltinSetWithId(Str, Id); } void SPIRVExtInstImport::validate() const { SPIRVEntry::validate(); IGC_ASSERT(!Str.empty() && "Invalid builtin set"); } void SPIRVMemoryModel::decode(std::istream &I) { SPIRVAddressingModelKind AddrModel; SPIRVMemoryModelKind MemModel; getDecoder(I) >> AddrModel >> MemModel; Module->setAddressingModel(AddrModel); Module->setMemoryModel(MemModel); } void SPIRVMemoryModel::validate() const { unsigned AM = Module->getAddressingModel(); unsigned MM = Module->getMemoryModel(); SPIRVCK(AM < SPIRVAddressingModelKind::AddressingModelCount, InvalidAddressingModel, "Actual is " + AM); SPIRVCK(MM < SPIRVMemoryModelKind::MemoryModelCount, InvalidMemoryModel, "Actual is " + MM); } void SPIRVSource::decode(std::istream &I) { SpvSourceLanguage Lang = SpvSourceLanguageUnknown; SPIRVWord Ver = SPIRVWORD_MAX; getDecoder(I) >> Lang >> Ver; Module->setSourceLanguage(Lang, Ver); } SPIRVSourceExtension::SPIRVSourceExtension(SPIRVModule *M, const std::string &SS) : SPIRVEntryNoId(M, 1 + getSizeInWords(SS)), S(SS){} void SPIRVSourceExtension::decode(std::istream &I) { getDecoder(I) >> S; Module->getSourceExtension().insert(S); } SPIRVExtension::SPIRVExtension(SPIRVModule *M, const std::string &SS) :SPIRVEntryNoId(M, 1 + getSizeInWords(SS)), S(SS){} void SPIRVExtension::decode(std::istream &I) { getDecoder(I) >> S; Module->getExtension().insert(S); } SPIRVCapability::SPIRVCapability(SPIRVModule *M, SPIRVCapabilityKind K) :SPIRVEntryNoId(M, 2), Kind(K){ } void SPIRVCapability::decode(std::istream &I) { getDecoder(I) >> Kind; Module->addCapability(Kind); } void SPIRVModuleProcessed::decode(std::istream &I) { getDecoder(I) >> S; Module->setModuleProcessed(S); } } // namespace spv intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVEntry.h000066400000000000000000000625141363533017100261720ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVEntry.h - Base Class for SPIR-V Entities -------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines the base class for SPIRV entities. /// //===----------------------------------------------------------------------===// #ifndef SPIRVENTRY_HPP_ #define SPIRVENTRY_HPP_ #include "SPIRVEnum.h" #include "SPIRVError.h" #include #include #include #include #include #include #include "Probe.h" namespace spv{ class SPIRVModule; class SPIRVDecoder; class SPIRVType; class SPIRVValue; class SPIRVDecorate; class SPIRVForward; class SPIRVMemberDecorate; class SPIRVLine; class SPIRVString; class SPIRVExtInst; // Add declaration of decode functions to a class. // Used inside class definition. #define _SPIRV_DCL_DEC \ void decode(std::istream &I); // Add implementation of decode functions to a class. // Used out side of class definition. #define _SPIRV_IMP_DEC0(Ty) \ void Ty::decode(std::istream &I) {} #define _SPIRV_IMP_DEC1(Ty,x) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x;} #define _SPIRV_IMP_DEC2(Ty,x,y) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y;} #define _SPIRV_IMP_DEC3(Ty,x,y,z) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z;} #define _SPIRV_IMP_DEC4(Ty,x,y,z,u) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u;} #define _SPIRV_IMP_DEC5(Ty,x,y,z,u,v) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v;} #define _SPIRV_IMP_DEC6(Ty,x,y,z,u,v,w) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> w;} #define _SPIRV_IMP_DEC7(Ty,x,y,z,u,v,w,r) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> w >> r;} #define _SPIRV_IMP_DEC8(Ty,x,y,z,u,v,w,r,s) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \ v >> w >> r >> s;} #define _SPIRV_IMP_DEC9(Ty,x,y,z,u,v,w,r,s,t) \ void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \ v >> w >> r >> s >> t;} // Add definition of decode functions to a class. // Used inside class definition. #define _SPIRV_DEF_DEC0 \ void decode(std::istream &I) {} #define _SPIRV_DEF_DEC1(x) \ void decode(std::istream &I) { getDecoder(I) >> x;} #define _SPIRV_DEF_DEC2(x,y) \ void decode(std::istream &I) { getDecoder(I) >> x >> y;} #define _SPIRV_DEF_DEC3(x,y,z) \ void decode(std::istream &I) { getDecoder(I) >> x >> y >> z;} #define _SPIRV_DEF_DEC3_OVERRIDE(x,y,z) \ void decode(std::istream &I) override { getDecoder(I) >> x >> y >> z;} #define _SPIRV_DEF_DEC4(x,y,z,u) \ void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u;} #define _SPIRV_DEF_DEC4_OVERRIDE(x,y,z,u) \ void decode(std::istream &I) override { getDecoder(I) >> x >> y >> z >> u;} #define _SPIRV_DEF_DEC5(x,y,z,u,v) \ void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v;} #define _SPIRV_DEF_DEC6(x,y,z,u,v,w) \ void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> w;} #define _SPIRV_DEF_DEC7(x,y,z,u,v,w,r) \ void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> w >> r;} #define _SPIRV_DEF_DEC8(x,y,z,u,v,w,r,s) \ void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> \ w >> r >> s;} #define _SPIRV_DEF_DEC9(x,y,z,u,v,w,r,s,t) \ void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> \ w >> r >> s >> t;} /// All SPIR-V in-memory-representation entities inherits from SPIRVEntry. /// Usually there are two flavors of constructors of SPIRV objects: /// /// 1. complete constructor: It requires all the parameters needed to create a /// SPIRV entity with complete information which can be validated. It is /// usually used by LLVM/SPIR-V translator to create SPIRV object /// corresponding to LLVM object. Such constructor calls validate() at /// the end of the construction. /// /// 2. incomplete constructor: For leaf classes, it has no parameters. /// It is usually called by SPIRVEntry::make(opcode) to create an incomplete /// object which should not be validated. Then setWordCount(count) is /// called to fix the size of the object if it is variable, and then the /// information is filled by the virtual function decode(istream). /// After that the object can be validated. /// /// To add a new SPIRV class: /// /// 1. It is recommended to name the class as SPIRVXXX if it has a fixed op code /// OpXXX. Although it is not mandatory, doing this facilitates adding it to /// the table of the factory function SPIRVEntry::create(). /// 2. Inherit from proper SPIRV class such as SPIRVType, SPIRVValue, /// SPIRVInstruction, etc. /// 3. Implement virtual function decode(), validate(). /// 4. If the object has variable size, implement virtual function /// setWordCount(). /// 5. If the class has special attributes, e.g. having no id, or having no /// type as a value, set them in the constructors. /// 6. Add the class to the Table of SPIRVEntry::create(). /// 7. Add the class to SPIRVToLLVM and LLVMToSPIRV. class SPIRVEntry { public: typedef std::vector CapVec; enum SPIRVEntryAttrib { SPIRVEA_DEFAULT = 0, SPIRVEA_NOID = 1, // Entry has no valid id SPIRVEA_NOTYPE = 2, // Value has no type }; // Complete constructor for objects with id SPIRVEntry(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVId TheId) :Module(M), OpCode(TheOpCode), Id(TheId), Attrib(SPIRVEA_DEFAULT), WordCount(TheWordCount), Line(nullptr){ validate(); } // Complete constructor for objects without id SPIRVEntry(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode) :Module(M), OpCode(TheOpCode), Id(SPIRVID_INVALID), Attrib(SPIRVEA_NOID), WordCount(TheWordCount), Line(nullptr){ validate(); } // Incomplete constructor SPIRVEntry(Op TheOpCode) :Module(NULL), OpCode(TheOpCode), Id(SPIRVID_INVALID), Attrib(SPIRVEA_DEFAULT), WordCount(0), Line(nullptr){} SPIRVEntry() :Module(NULL), OpCode(OpNop), Id(SPIRVID_INVALID), Attrib(SPIRVEA_DEFAULT), WordCount(0), Line(nullptr){} virtual ~SPIRVEntry(){} bool exist(SPIRVId)const; template T* get(SPIRVId TheId)const { return static_cast(getEntry(TheId));} SPIRVEntry *getEntry(SPIRVId) const; SPIRVEntry *getOrCreate(SPIRVId TheId) const; SPIRVValue *getValue(SPIRVId TheId)const; std::vector getValues(const std::vector&)const; std::vector getIds(const std::vector)const; SPIRVType *getValueType(SPIRVId TheId)const; std::vector getValueTypes(const std::vector&)const; virtual SPIRVDecoder getDecoder(std::istream &); SPIRVErrorLog &getErrorLog()const; SPIRVId getId() const { IGC_ASSERT(hasId()); return Id;} SPIRVLine *getLine() const { return Line;} SPIRVLinkageTypeKind getLinkageType() const; Op getOpCode() const { return OpCode;} SPIRVModule *getModule() const { return Module;} virtual CapVec getRequiredCapability() const { return CapVec();} const std::string& getName() const { return Name;} bool hasDecorate(Decoration Kind, size_t Index = 0, SPIRVWord *Result=0)const; std::set getDecorate(Decoration Kind, size_t Index = 0)const; std::vector getDecorationStringLiteral(Decoration Kind) const; bool hasId() const { return !(Attrib & SPIRVEA_NOID);} bool hasLine() const { return Line != nullptr;} bool hasLinkageType() const; bool isAtomic() const { return isAtomicOpCode(OpCode);} bool isBasicBlock() const { return isLabel();} bool isBuiltinCall() const { return OpCode == OpExtInst;} bool isDecorate()const { return OpCode == OpDecorate;} bool isMemberDecorate()const { return OpCode == OpMemberDecorate;} bool isForward() const { return OpCode == OpForward;} bool isLabel() const { return OpCode == OpLabel;} bool isUndef() const { return OpCode == OpUndef;} bool isControlBarrier() const { return OpCode == OpControlBarrier;} bool isMemoryBarrier() const { return OpCode == OpMemoryBarrier;} bool isVariable() const { return OpCode == OpVariable;} virtual bool isInst() const { return false;} void addDecorate(const SPIRVDecorate *); void addDecorate(Decoration Kind); void addDecorate(Decoration Kind, SPIRVWord Literal); void eraseDecorate(Decoration); void addMemberDecorate(const SPIRVMemberDecorate *); void addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind); void addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind, SPIRVWord Literal); void eraseMemberDecorate(SPIRVWord MemberNumber, Decoration Kind); void setHasNoId() { Attrib |= SPIRVEA_NOID;} void setId(SPIRVId TheId) { Id = TheId;} void setLine(SPIRVLine*); void setDIScope(SPIRVExtInst*); SPIRVExtInst* getDIScope(); void setLinkageType(SPIRVLinkageTypeKind); void setModule(SPIRVModule *TheModule); void setName(const std::string& TheName); virtual void setScope(SPIRVEntry *Scope){}; void takeAnnotations(SPIRVForward *); void takeDecorates(SPIRVEntry *); void takeMemberDecorates(SPIRVEntry *); void takeLine(SPIRVEntry *); /// After a SPIRV entry is created during reading SPIRV binary by default /// constructor, this function is called to allow the SPIRV entry to resize /// its variable sized member before decoding the remaining words. virtual void setWordCount(SPIRVWord TheWordCount); /// Create an empty SPIRV object by op code, e.g. OpTypeInt creates /// SPIRVTypeInt. static SPIRVEntry *create(Op); friend std::istream &operator>>(std::istream &I, SPIRVEntry &E); virtual void decode(std::istream &I); friend class SPIRVDecoder; /// Checks the integrity of the object. virtual void validate()const { IGC_ASSERT(Module && "Invalid module"); IGC_ASSERT(OpCode != OpNop && "Invalid op code"); IGC_ASSERT((!hasId() || isValid(Id)) && "Invalid Id"); } void validateFunctionControlMask(SPIRVWord FCtlMask)const; void validateValues(const std::vector &)const; void validateBuiltin(SPIRVWord, SPIRVWord)const; virtual bool hasNoScope() { return false; } virtual bool isOpLine() { return false; } virtual bool isOpNoLine() { return false; } virtual bool isScope() { return false; } virtual bool startsScope() { return false; } virtual bool endsScope() { return false; } virtual bool isString() { return false; } virtual bool isConstant() { return false; } protected: /// An entry may have multiple FuncParamAttr decorations. typedef std::multimap DecorateMapType; typedef std::map, const SPIRVMemberDecorate*> MemberDecorateMapType; bool canHaveMemberDecorates() const { return OpCode == OpTypeStruct || OpCode == OpForward; } MemberDecorateMapType& getMemberDecorates() { IGC_ASSERT(canHaveMemberDecorates()); return MemberDecorates; } SPIRVModule *Module; Op OpCode; SPIRVId Id; std::string Name; unsigned Attrib; SPIRVWord WordCount; DecorateMapType Decorates; MemberDecorateMapType MemberDecorates; SPIRVLine *Line; SPIRVExtInst* diScope = nullptr; }; class SPIRVEntryNoIdGeneric:public SPIRVEntry { public: SPIRVEntryNoIdGeneric(SPIRVModule *M, unsigned TheWordCount, Op OC) :SPIRVEntry(M, TheWordCount, OC){ setAttr(); } SPIRVEntryNoIdGeneric(Op OC):SPIRVEntry(OC){ setAttr(); } protected: void setAttr() { setHasNoId(); } }; template class SPIRVEntryNoId:public SPIRVEntryNoIdGeneric { public: SPIRVEntryNoId(SPIRVModule *M, unsigned TheWordCount) :SPIRVEntryNoIdGeneric(M, TheWordCount, OC){} SPIRVEntryNoId():SPIRVEntryNoIdGeneric(OC){} }; template class SPIRVEntryOpCodeOnly:public SPIRVEntryNoId { public: SPIRVEntryOpCodeOnly(){ SPIRVEntry::WordCount = 1; validate(); } protected: _SPIRV_DEF_DEC0 void validate()const { IGC_ASSERT(isValid(SPIRVEntry::OpCode)); } }; class SPIRVAnnotationGeneric:public SPIRVEntryNoIdGeneric { public: // Complete constructor SPIRVAnnotationGeneric(const SPIRVEntry *TheTarget, unsigned TheWordCount, Op OC) :SPIRVEntryNoIdGeneric((TheTarget ? TheTarget->getModule() : NULL), TheWordCount, OC), Target(TheTarget ? TheTarget->getId() : SPIRVID_INVALID){} // Incomplete constructor SPIRVAnnotationGeneric(Op OC):SPIRVEntryNoIdGeneric(OC), Target(SPIRVID_INVALID){} SPIRVId getTargetId()const { return Target;} SPIRVForward *getOrCreateTarget()const; void setTargetId(SPIRVId T) { Target = T;} protected: SPIRVId Target; }; template class SPIRVAnnotation:public SPIRVAnnotationGeneric { public: // Complete constructor SPIRVAnnotation(const SPIRVEntry *TheTarget, unsigned TheWordCount) :SPIRVAnnotationGeneric(TheTarget, TheWordCount, OC){} // Incomplete constructor SPIRVAnnotation():SPIRVAnnotationGeneric(OC){} }; class SPIRVEntryPoint:public SPIRVAnnotation { public: SPIRVEntryPoint(SPIRVModule *TheModule, SPIRVExecutionModelKind, SPIRVId TheId, const std::string &TheName); SPIRVEntryPoint():ExecModel(ExecutionModelKernel){} _SPIRV_DCL_DEC protected: SPIRVExecutionModelKind ExecModel; std::string Name; CapVec getRequiredCapability() const { return getVec(getCapability(ExecModel)); } }; class SPIRVName:public SPIRVAnnotation { public: // Complete constructor SPIRVName(const SPIRVEntry *TheTarget, const std::string& TheStr); // Incomplete constructor SPIRVName(){} protected: _SPIRV_DCL_DEC void validate() const; std::string Str; }; class SPIRVMemberName:public SPIRVAnnotation { public: static const SPIRVWord FixedWC = 3; // Complete constructor SPIRVMemberName(const SPIRVEntry *TheTarget, SPIRVWord TheMemberNumber, const std::string& TheStr) :SPIRVAnnotation(TheTarget, FixedWC + getSizeInWords(TheStr)), MemberNumber(TheMemberNumber), Str(TheStr){ validate(); } // Incomplete constructor SPIRVMemberName():MemberNumber(SPIRVWORD_MAX){} protected: _SPIRV_DCL_DEC void validate() const; SPIRVWord MemberNumber; std::string Str; }; class SPIRVString:public SPIRVEntry { static const Op OC = OpString; static const SPIRVWord FixedWC = 2; public: SPIRVString(SPIRVModule *M, SPIRVId TheId, const std::string &TheStr) :SPIRVEntry(M, FixedWC + getSizeInWords(TheStr), OC, TheId), Str(TheStr){} SPIRVString():SPIRVEntry(OC){} _SPIRV_DCL_DEC const std::string &getStr()const { return Str;} bool isString() { return true; } protected: std::string Str; }; class SPIRVLine:public SPIRVEntryNoIdGeneric { public: static const SPIRVWord WC = 5; // Complete constructor SPIRVLine(SPIRVModule* M, SPIRVId TheFileName, SPIRVWord TheLine, SPIRVWord TheColumn) :SPIRVEntryNoIdGeneric(M, WC, OpLine), FileName(TheFileName), Line(TheLine), Column(TheColumn){ validate(); } // Incomplete constructor SPIRVLine(): SPIRVEntryNoIdGeneric(OpLine), FileName(SPIRVID_INVALID), Line(SPIRVWORD_MAX), Column(SPIRVWORD_MAX) {} SPIRVWord getColumn() const { return Column; } void setColumn(SPIRVWord column) { Column = column; } SPIRVId getFileName() const { return FileName; } const std::string &getFileNameStr() const { return get(FileName)->getStr(); } void setFileName(SPIRVId fileName) { FileName = fileName; } SPIRVWord getLine() const { return Line; } void setLine(SPIRVWord line) { Line = line; } bool isOpLine() { return true; } protected: _SPIRV_DCL_DEC void validate() const; SPIRVId FileName; SPIRVWord Line; SPIRVWord Column; }; class SPIRVNoLine :public SPIRVEntryNoIdGeneric { public: static const SPIRVWord WC = 1; // Complete constructor SPIRVNoLine(SPIRVModule* M) :SPIRVEntryNoIdGeneric(M, WC, OpNoLine) { validate(); } // Incomplete constructor SPIRVNoLine() : SPIRVEntryNoIdGeneric(OpNoLine) {} bool isOpLine() { return true; } protected: _SPIRV_DCL_DEC void validate() const; }; class SPIRVExecutionMode:public SPIRVAnnotation { public: // Complete constructor for LocalSize, LocalSizeHint SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode, SPIRVWord x, SPIRVWord y, SPIRVWord z) :SPIRVAnnotation(TheTarget, 6), ExecMode(TheExecMode){ WordLiterals.push_back(x); WordLiterals.push_back(y); WordLiterals.push_back(z); } // Complete constructor for VecTypeHint SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode, SPIRVWord code) :SPIRVAnnotation(TheTarget, 4), ExecMode(TheExecMode) { WordLiterals.push_back(code); } // Complete constructor for ContractionOff SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode) :SPIRVAnnotation(TheTarget, 3), ExecMode(TheExecMode){} // Incomplete constructor SPIRVExecutionMode():ExecMode(ExecutionModeCount){} SPIRVExecutionModeKind getExecutionMode()const { return ExecMode;} const std::vector& getLiterals()const { return WordLiterals;} CapVec getRequiredCapability() const { return getVec(getCapability(ExecMode)); } protected: _SPIRV_DCL_DEC SPIRVExecutionModeKind ExecMode; std::vector WordLiterals; }; class SPIRVComponentExecutionModes { typedef std::map SPIRVExecutionModeMap; public: void addExecutionMode(SPIRVExecutionMode *ExecMode) { ExecModes[ExecMode->getExecutionMode()] = ExecMode; } SPIRVExecutionMode *getExecutionMode(SPIRVExecutionModeKind EMK)const { auto Loc = ExecModes.find(EMK); if (Loc == ExecModes.end()) return nullptr; return Loc->second; } protected: SPIRVExecutionModeMap ExecModes; }; class SPIRVExtInstImport:public SPIRVEntry { public: const static Op OC = OpExtInstImport; // Complete constructor SPIRVExtInstImport(SPIRVModule *TheModule, SPIRVId TheId, const std::string& TheStr); // Incomplete constructor SPIRVExtInstImport():SPIRVEntry(OC){} protected: _SPIRV_DCL_DEC void validate() const; std::string Str; }; class SPIRVMemoryModel:public SPIRVEntryNoId { public: SPIRVMemoryModel(SPIRVModule *M):SPIRVEntryNoId(M, 3){} SPIRVMemoryModel(){} _SPIRV_DCL_DEC void validate() const; }; class SPIRVSource:public SPIRVEntryNoId { public: SPIRVSource(SPIRVModule *M):SPIRVEntryNoId(M, 3){} SPIRVSource(){} _SPIRV_DCL_DEC }; class SPIRVSourceExtension:public SPIRVEntryNoId { public: SPIRVSourceExtension(SPIRVModule *M, const std::string &SS); SPIRVSourceExtension(){} _SPIRV_DCL_DEC private: std::string S; }; class SPIRVExtension:public SPIRVEntryNoId { public: SPIRVExtension(SPIRVModule *M, const std::string &SS); SPIRVExtension(){} _SPIRV_DCL_DEC private: std::string S; }; class SPIRVCapability:public SPIRVEntryNoId { public: SPIRVCapability(SPIRVModule *M, SPIRVCapabilityKind K); SPIRVCapability():Kind(CapabilityNone){} _SPIRV_DCL_DEC private: SPIRVCapabilityKind Kind; }; class SPIRVModuleProcessed: public SPIRVEntryNoId { public: SPIRVModuleProcessed(SPIRVModule *M):SPIRVEntryNoId(M, 2){} SPIRVModuleProcessed(){} _SPIRV_DCL_DEC private: std::string S; }; template T* bcast(SPIRVEntry *E) { return static_cast(E); } template bool isa(SPIRVEntry *E) { return E ? E->getOpCode() == OC : false; } // ToDo: The following typedef's are place holders for SPIRV entity classes // to be implemented. // Each time a new class is implemented, remove the corresponding typedef. // This is also an indication of how much work is left. #define _SPIRV_OP(x, ...) typedef SPIRVEntryOpCodeOnly SPIRV##x; _SPIRV_OP(Nop) _SPIRV_OP(SourceContinued) _SPIRV_OP(TypeMatrix) _SPIRV_OP(TypeRuntimeArray) _SPIRV_OP(TypeForwardPointer) _SPIRV_OP(ImageTexelPointer) _SPIRV_OP(ImageSampleDrefImplicitLod) _SPIRV_OP(ImageSampleDrefExplicitLod) _SPIRV_OP(ImageSampleProjImplicitLod) _SPIRV_OP(ImageSampleProjExplicitLod) _SPIRV_OP(ImageSampleProjDrefImplicitLod) _SPIRV_OP(ImageSampleProjDrefExplicitLod) _SPIRV_OP(ImageFetch) _SPIRV_OP(ImageGather) _SPIRV_OP(ImageDrefGather) _SPIRV_OP(QuantizeToF16) _SPIRV_OP(Transpose) _SPIRV_OP(ArrayLength) _SPIRV_OP(MatrixTimesScalar) _SPIRV_OP(VectorTimesMatrix) _SPIRV_OP(MatrixTimesVector) _SPIRV_OP(MatrixTimesMatrix) _SPIRV_OP(OuterProduct) _SPIRV_OP(IAddCarry) _SPIRV_OP(ISubBorrow) _SPIRV_OP(BitFieldInsert) _SPIRV_OP(BitFieldSExtract) _SPIRV_OP(BitFieldUExtract) _SPIRV_OP(DPdx) _SPIRV_OP(DPdy) _SPIRV_OP(Fwidth) _SPIRV_OP(DPdxFine) _SPIRV_OP(DPdyFine) _SPIRV_OP(FwidthFine) _SPIRV_OP(DPdxCoarse) _SPIRV_OP(DPdyCoarse) _SPIRV_OP(FwidthCoarse) _SPIRV_OP(EmitVertex) _SPIRV_OP(EndPrimitive) _SPIRV_OP(EmitStreamVertex) _SPIRV_OP(EndStreamPrimitive) _SPIRV_OP(Kill) _SPIRV_OP(ImageSparseSampleImplicitLod) _SPIRV_OP(ImageSparseSampleExplicitLod) _SPIRV_OP(ImageSparseSampleDrefImplicitLod) _SPIRV_OP(ImageSparseSampleDrefExplicitLod) _SPIRV_OP(ImageSparseSampleProjImplicitLod) _SPIRV_OP(ImageSparseSampleProjExplicitLod) _SPIRV_OP(ImageSparseSampleProjDrefImplicitLod) _SPIRV_OP(ImageSparseSampleProjDrefExplicitLod) _SPIRV_OP(ImageSparseFetch) _SPIRV_OP(ImageSparseGather) _SPIRV_OP(ImageSparseDrefGather) _SPIRV_OP(ImageSparseTexelsResident) #undef _SPIRV_OP } #endif /* SPIRVENTRY_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVEnum.h000066400000000000000000000232501363533017100257670ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVEnum.h - SPIR-V enums --------------------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines SPIR-V enums. /// //===----------------------------------------------------------------------===// #ifndef SPIRVENUM_HPP_ #define SPIRVENUM_HPP_ #include "spirv.hpp" #include "SPIRVOpCode.h" #include namespace spv{ typedef uint32_t SPIRVWord; typedef uint32_t SPIRVId; #define SPIRVID_MAX ~0U #define SPIRVID_INVALID ~0U #define SPIRVWORD_MAX ~0U inline bool isValid(SPIRVId Id) { return Id != SPIRVID_INVALID;} inline SPIRVWord mkWord(unsigned WordCount, Op OpCode) { return (WordCount << 16) | OpCode; } const SPIRVWord SPIRVMagicNumber = spv::MagicNumber; enum SPIRVVersionSupported { fullyCompliant = spv::Version }; enum SPIRVGeneratorKind { SPIRVGEN_AMDOpenSourceLLVMSPIRVTranslator = 1, }; enum SPIRVInstructionSchemaKind { SPIRVISCH_Default, }; typedef spv::Capability SPIRVCapabilityKind; typedef spv::ExecutionModel SPIRVExecutionModelKind; typedef spv::ExecutionMode SPIRVExecutionModeKind; typedef spv::AccessQualifier SPIRVAccessQualifierKind; typedef spv::AddressingModel SPIRVAddressingModelKind; typedef spv::LinkageType SPIRVLinkageTypeKind; typedef spv::MemoryModel SPIRVMemoryModelKind; typedef spv::StorageClass SPIRVStorageClassKind; typedef spv::FunctionControlMask SPIRVFunctionControlMaskKind; typedef spv::FPRoundingMode SPIRVFPRoundingModeKind; typedef spv::FunctionParameterAttribute SPIRVFuncParamAttrKind; typedef spv::BuiltIn SPIRVBuiltinVariableKind; typedef spv::MemoryAccessMask SPIRVMemoryAccessKind; typedef spv::GroupOperation SPIRVGroupOperationKind; typedef spv::Dim SPIRVImageDimKind; template SPIRVCapabilityKind getCapability(K Key) { return SPIRVMap::map(Key); } template<> inline void SPIRVMap::init() { add(ExecutionModelVertex, CapabilityShader); add(ExecutionModelTessellationControl, CapabilityTessellation); add(ExecutionModelTessellationEvaluation, CapabilityShader); add(ExecutionModelGeometry, CapabilityGeometry); add(ExecutionModelFragment, CapabilityShader); add(ExecutionModelGLCompute, CapabilityShader); add(ExecutionModelKernel, CapabilityKernel); } inline bool isValid(SPIRVExecutionModelKind E) { return (unsigned)E < (unsigned)ExecutionModelCount; } template<> inline void SPIRVMap::init() { add(ExecutionModeInvocations, CapabilityGeometry); add(ExecutionModeSpacingEqual, CapabilityTessellation); add(ExecutionModeSpacingFractionalEven, CapabilityTessellation); add(ExecutionModeSpacingFractionalOdd, CapabilityTessellation); add(ExecutionModeVertexOrderCw, CapabilityTessellation); add(ExecutionModeVertexOrderCcw, CapabilityTessellation); add(ExecutionModePixelCenterInteger, CapabilityShader); add(ExecutionModeOriginUpperLeft, CapabilityShader); add(ExecutionModeOriginLowerLeft, CapabilityShader); add(ExecutionModeEarlyFragmentTests, CapabilityShader); add(ExecutionModePointMode, CapabilityTessellation); add(ExecutionModeXfb, CapabilityShader); add(ExecutionModeDepthReplacing, CapabilityShader); add(ExecutionModeDepthGreater, CapabilityShader); add(ExecutionModeDepthLess, CapabilityShader); add(ExecutionModeDepthUnchanged, CapabilityShader); add(ExecutionModeLocalSize, CapabilityNone); add(ExecutionModeLocalSizeHint, CapabilityKernel); add(ExecutionModeInputPoints, CapabilityGeometry); add(ExecutionModeInputLines, CapabilityGeometry); add(ExecutionModeInputLinesAdjacency, CapabilityGeometry); add(ExecutionModeInputTriangles, CapabilityTessellation); add(ExecutionModeInputTrianglesAdjacency, CapabilityGeometry); add(ExecutionModeInputQuads, CapabilityGeometry); add(ExecutionModeInputIsolines, CapabilityGeometry); add(ExecutionModeOutputVertices, CapabilityTessellation); add(ExecutionModeOutputPoints, CapabilityGeometry); add(ExecutionModeOutputLineStrip, CapabilityGeometry); add(ExecutionModeOutputTriangleStrip, CapabilityGeometry); add(ExecutionModeVecTypeHint, CapabilityKernel); add(ExecutionModeContractionOff, CapabilityKernel); add(ExecutionModeInitializer, CapabilityKernel); add(ExecutionModeFinalizer, CapabilityKernel); add(ExecutionModeSubgroupSize, CapabilitySubgroupDispatch); add(ExecutionModeSubgroupsPerWorkgroup, CapabilitySubgroupDispatch); } inline bool isValid(SPIRVExecutionModeKind E) { return (unsigned)E < (unsigned)ExecutionModeCount; } inline bool isValid(SPIRVLinkageTypeKind L) { return (unsigned)L < (unsigned)LinkageTypeCount; } template<> inline void SPIRVMap::init() { add(StorageClassUniformConstant, CapabilityNone); add(StorageClassInput, CapabilityShader); add(StorageClassUniform, CapabilityShader); add(StorageClassOutput, CapabilityShader); add(StorageClassWorkgroupLocal, CapabilityNone); add(StorageClassWorkgroupGlobal, CapabilityNone); add(StorageClassPrivateGlobal, CapabilityShader); add(StorageClassFunction, CapabilityShader); add(StorageClassGeneric, CapabilityKernel); add(StorageClassAtomicCounter, CapabilityShader); } inline bool isValid(SPIRVStorageClassKind StorageClass) { return (unsigned)StorageClass < (unsigned)StorageClassCount; } inline bool isValid(SPIRVFuncParamAttrKind FPA) { return (unsigned)FPA < (unsigned)FunctionParameterAttributeCount; } enum SPIRVExtInstSetKind { SPIRVEIS_OpenCL, SPIRVEIS_DebugInfo, SPIRVEIS_Count, }; inline bool isValid(SPIRVExtInstSetKind BIS) { return (unsigned)BIS < (unsigned)SPIRVEIS_Count; } template<> inline void SPIRVMap::init() { add(SPIRVEIS_OpenCL, "OpenCL.std"); add(SPIRVEIS_DebugInfo, "SPIRV.debug"); } typedef SPIRVMap SPIRVBuiltinSetNameMap; inline bool isValid(SPIRVBuiltinVariableKind Kind) { return (unsigned)Kind < (unsigned)BuiltInCount; } inline bool isValid(Scope Kind) { return (unsigned)Kind <= (unsigned)ScopeInvocation; } inline bool isValidSPIRVMemSemanticsMask(SPIRVWord MemMask) { return MemMask < 1 << ((unsigned)MemorySemanticsImageMemoryShift + 1); } //enum SPIRVSamplerAddressingModeKind typedef spv::SamplerAddressingMode SPIRVSamplerAddressingModeKind; //enum SPIRVSamplerFilterModeKind typedef spv::SamplerFilterMode SPIRVSamplerFilterModeKind; inline bool isValid(SPIRVGroupOperationKind G) { return (unsigned)G < (unsigned)GroupOperationCount; } inline unsigned getImageDimension(SPIRVImageDimKind K) { switch(K){ case Dim1D: return 1; case Dim2D: return 2; case Dim3D: return 3; case DimCube: return 2; case DimRect: return 2; case DimBuffer: return 1; default: return 0; } } } #endif /* SPIRVENUM_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVError.h000066400000000000000000000133411363533017100261540ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVError.h - SPIR-V error code and checking -------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// // // This file defines SPIRV error code and checking utility. // //===----------------------------------------------------------------------===// #ifndef SPIRVERROR_HPP_ #define SPIRVERROR_HPP_ #include "SPIRVUtil.h" #include "SPIRVDebug.h" #include "Probe.h" #include #include namespace spv{ // Check condition and set error code and error msg. // To use this macro, function checkError must be defined in the scope. #define SPIRVCK(Condition,ErrCode,ErrMsg) \ getErrorLog().checkError(Condition, SPIRVEC_##ErrCode, std::string()+ErrMsg,\ #Condition, __FILE__, __LINE__) // Check condition and set error code and error msg. If fail returns false. #define SPIRVCKRT(Condition,ErrCode,ErrMsg) \ if (!getErrorLog().checkError(Condition, SPIRVEC_##ErrCode,\ std::string()+ErrMsg, #Condition, __FILE__, __LINE__))\ return false; // Defines error code enum type SPIRVErrorCode. enum SPIRVErrorCode { #define _SPIRV_OP(x,y) SPIRVEC_##x, #include "SPIRVErrorEnum.h" #undef _SPIRV_OP }; // Defines OpErorMap which maps error code to a string describing the error. template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,y) add(SPIRVEC_##x, std::string(#x)+": "+y); #include "SPIRVErrorEnum.h" #undef _SPIRV_OP } typedef SPIRVMap SPIRVErrorMap; class SPIRVErrorLog { public: SPIRVErrorLog():ErrorCode(SPIRVEC_Success){} SPIRVErrorCode getError(std::string& ErrMsg) { ErrMsg = ErrorMsg; return ErrorCode; } void setError(SPIRVErrorCode ErrCode, const std::string& ErrMsg) { ErrorCode = ErrCode; ErrorMsg = ErrMsg; } // Check if Condition is satisfied and set ErrCode and DetailedMsg // if not. Returns true if no error. bool checkError(bool Condition, SPIRVErrorCode ErrCode, const std::string& DetailedMsg = "", const char *CondString = nullptr, const char *FileName = nullptr, unsigned LineNumber = 0); protected: SPIRVErrorCode ErrorCode; std::string ErrorMsg; }; inline bool SPIRVErrorLog::checkError(bool Cond, SPIRVErrorCode ErrCode, const std::string& Msg, const char *CondString, const char *FileName, unsigned LineNo) { std::stringstream SS; if (Cond) return Cond; // Do not overwrite previous failure. if (ErrorCode != SPIRVEC_Success) return Cond; SS << SPIRVErrorMap::map(ErrCode) << " " << Msg; if (SPIRVDbgErrorMsgIncludesSourceInfo) SS <<" [Src: " << FileName << ":" << LineNo << " " << CondString << " ]"; setError(ErrCode, SS.str()); if (SPIRVDbgAssertOnError) { bildbgs() << SS.str() << '\n'; bildbgs().flush(); IGC_ASSERT_EXIT(0); } return Cond; } } #endif /* SPIRVERROR_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVErrorEnum.h000066400000000000000000000006121363533017100267760ustar00rootroot00000000000000/* The error code name should be meaningful since it is part of error message */ _SPIRV_OP(Success,"") _SPIRV_OP(InvalidTargetTriple, "Expects spir-unknown-unknown or spir64-unknown-unknown.") _SPIRV_OP(InvalidAddressingModel, "Expects 0-2.") _SPIRV_OP(InvalidMemoryModel, "Expects 0-3.") _SPIRV_OP(InvalidFunctionControlMask,"") _SPIRV_OP(InvalidBuiltinSetName, "Expects OpenCL12, OpenCL20.") intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVExtInst.h000066400000000000000000000102301363533017100264530ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVBuiltin.h - SPIR-V extended instruction --------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines SPIR-V extended instructions. /// //===----------------------------------------------------------------------===// #ifndef SPIRVBUILTIN_HPP_ #define SPIRVBUILTIN_HPP_ #include "SPIRVUtil.h" #include "OpenCL.std.h" #include "SPIRV.DebugInfo.h" #include #include namespace spv{ inline bool isOpenCLBuiltinSet (SPIRVExtInstSetKind Set) { return Set == SPIRVEIS_OpenCL; } inline bool isSPIRVDebugInfoSet(SPIRVExtInstSetKind Set) { return Set == SPIRVEIS_DebugInfo; } typedef OpenCLLIB::Entrypoints OCLExtOpKind; typedef SPIRVDebugInfo::Entrypoints OCLExtOpDbgKind; template<> inline void SPIRVMap::init() { #define _OCL_EXT_OP(name, num) add(OpenCLLIB::name, #name); #include "OpenCL.stdfuncs.h" #undef _OCL_EXT_OP } SPIRV_DEF_NAMEMAP(OCLExtOpKind, OCLExtOpMap) template<> inline void SPIRVMap::init() { #define _OCL_EXT_OP(name, num) add(SPIRVDebugInfo::name, #name); #include "SPIRV.DebugInfofuncs.h" #undef _OCL_EXT_OP } SPIRV_DEF_NAMEMAP(OCLExtOpDbgKind, OCLExtOpDbgMap) } #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVFunction.cpp000066400000000000000000000165431363533017100272120ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVFunction.cpp - Class to represent a SPIR-V Function --*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements Function class for SPIRV. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// #include "SPIRVFunction.h" #include "SPIRVInstruction.h" #include "SPIRVStream.h" #include "Probe.h" using namespace spv; SPIRVFunctionParameter::SPIRVFunctionParameter(SPIRVType *TheType, SPIRVId TheId, SPIRVFunction *TheParent, unsigned TheArgNo): SPIRVValue(TheParent->getModule(), 3, OpFunctionParameter, TheType, TheId), ParentFunc(TheParent), ArgNo(TheArgNo){ validate(); } void SPIRVFunctionParameter::foreachAttr( std::functionFunc){ auto Locs = Decorates.equal_range(DecorationFuncParamAttr); for (auto I = Locs.first, E = Locs.second; I != E; ++I){ auto Attr = static_cast( I->second->getLiteral(0)); IGC_ASSERT(isValid(Attr)); Func(Attr); } } SPIRVDecoder SPIRVFunction::getDecoder(std::istream &IS) { return SPIRVDecoder(IS, *this); } void SPIRVFunction::decode(std::istream &I) { SPIRVDecoder Decoder = getDecoder(I); Decoder >> Type >> Id >> FCtrlMask >> FuncType; Module->addFunction(this); Decoder.getWordCountAndOpCode(); while (!I.eof()) { if (Decoder.OpCode == OpFunctionEnd) break; switch(Decoder.OpCode) { case OpFunctionParameter: { auto Param = static_cast(Decoder.getEntry()); if (Param != NULL){ Param->setParent(this); Parameters.push_back(Param); Decoder.getWordCountAndOpCode(); continue; } else{ IGC_ASSERT_EXIT(0); } break; } case OpLabel: { decodeBB(Decoder); break; } default: IGC_ASSERT_EXIT(0 && "Invalid SPIRV format"); break; } } } /// Decode basic block and contained instructions. /// Do it here instead of in BB:decode to avoid back track in input stream. void SPIRVFunction::decodeBB(SPIRVDecoder &Decoder) { SPIRVBasicBlock* const BB = static_cast(Decoder.getEntry()); if (nullptr != BB){ SPIRVLine* line = nullptr; SPIRVExtInst* diScope = nullptr; addBasicBlock(BB); Decoder.setScope(BB); while (Decoder.getWordCountAndOpCode()) { if (Decoder.OpCode == OpFunctionEnd || Decoder.OpCode == OpLabel) { break; } switch (Decoder.OpCode) { case OpNop: case OpName: case OpDecorate: // We don't currently have a use for these structured control flow // opcodes, just ignore them for now. case OpSelectionMerge: // OpUndef is in the strange "Miscellaneous Instructions" category which means // that it can be used as a constant or as an instruction. LLVM represents it // as an constant so if we encounter it as an instruction, don't add it to the // basic block but store it so it can be referenced later and emitted in LLVM // as a constant. case OpUndef: Decoder.getEntry(); continue; default: break; } auto newEntry = Decoder.getEntry(); if (newEntry->isInst() && !newEntry->isScope()) { SPIRVInstruction *Inst = static_cast(newEntry); BB->addInstruction(Inst); Inst->setLine(line); Inst->setDIScope(diScope); } else if (newEntry->isOpLine()) line = static_cast(newEntry); else if (newEntry->isOpNoLine()) line = nullptr; else if (newEntry->startsScope()) diScope = static_cast(newEntry); else if (newEntry->endsScope()) diScope = nullptr; else IGC_ASSERT(false && "Non-instruction entry found"); } Decoder.setScope(this); } else{ IGC_ASSERT_EXIT(0); } } void SPIRVFunction::foreachReturnValueAttr( std::functionFunc){ auto Locs = Decorates.equal_range(DecorationFuncParamAttr); for (auto I = Locs.first, E = Locs.second; I != E; ++I){ auto Attr = static_cast( I->second->getLiteral(0)); IGC_ASSERT(isValid(Attr)); Func(Attr); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVFunction.h000066400000000000000000000167401363533017100266560ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVFunction.h - Class to represent a SPIR-V function ----*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines Function class for SPIRV. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// #ifndef SPIRVFUNCTION_HPP_ #define SPIRVFUNCTION_HPP_ #include "SPIRVValue.h" #include "SPIRVBasicBlock.h" #include "Probe.h" namespace spv{ class SPIRVDecoder; class SPIRVFunctionParameter: public SPIRVValue { public: SPIRVFunctionParameter(SPIRVType *TheType, SPIRVId TheId, SPIRVFunction *TheParent, unsigned TheArgNo); SPIRVFunctionParameter():SPIRVValue(OpFunctionParameter), ParentFunc(nullptr), ArgNo(0){} unsigned getArgNo()const { return ArgNo;} void foreachAttr(std::function); void addAttr(SPIRVFuncParamAttrKind Kind) { addDecorate(new SPIRVDecorate(DecorationFuncParamAttr, this, Kind)); } void setParent(SPIRVFunction *Parent) { ParentFunc = Parent;} bool hasAttr(SPIRVFuncParamAttrKind Kind) const { return (getDecorate(DecorationFuncParamAttr).count(Kind) > 0) ; } bool isByVal()const { return hasAttr(SPIRVFuncParamAttrKind::FunctionParameterAttributeByVal); } bool isZext()const { return hasAttr(SPIRVFuncParamAttrKind::FunctionParameterAttributeZext); } bool hasMaxByteOffset(SPIRVWord &offset) const { return hasDecorate(DecorationMaxByteOffset, 0, &offset); } CapVec getRequiredCapability() const { if (hasLinkageType() && getLinkageType() == SPIRVLinkageTypeKind::LinkageTypeImport) return getVec(SPIRVCapabilityKind::CapabilityLinkage); return CapVec(); } protected: void validate()const { SPIRVValue::validate(); IGC_ASSERT(ParentFunc && "Invalid parent function"); } _SPIRV_DEF_DEC2(Type, Id) private: SPIRVFunction *ParentFunc; unsigned ArgNo; }; class SPIRVFunction: public SPIRVValue, public SPIRVComponentExecutionModes { public: // Complete constructor. It does not construct basic blocks. SPIRVFunction(SPIRVModule *M, SPIRVTypeFunction *FunctionType, SPIRVId TheId) :SPIRVValue(M, 5, OpFunction, FunctionType->getReturnType(), TheId), FuncType(FunctionType), FCtrlMask(SPIRVFunctionControlMaskKind::FunctionControlMaskNone) { addAllArguments(TheId + 1); validate(); } // Incomplete constructor SPIRVFunction():SPIRVValue(OpFunction),FuncType(NULL), FCtrlMask(SPIRVFunctionControlMaskKind::FunctionControlMaskNone){} SPIRVDecoder getDecoder(std::istream &IS); SPIRVTypeFunction *getFunctionType() const { return FuncType;} SPIRVWord getFuncCtlMask() const { return FCtrlMask;} size_t getNumBasicBlock() const { return BBVec.size();} SPIRVBasicBlock *getBasicBlock(size_t i) const { return BBVec[i];} size_t getNumArguments() const { return getFunctionType()->getNumParameters(); } SPIRVId getArgumentId(size_t i)const { return Parameters[i]->getId();} SPIRVFunctionParameter *getArgument(size_t i) const { return Parameters[i]; } void foreachArgument(std::functionFunc) { for (size_t I = 0, E = getNumArguments(); I != E; ++I) Func(getArgument(I)); } void foreachReturnValueAttr(std::function); void setFunctionControlMask(SPIRVWord Mask) { FCtrlMask = Mask; } void takeExecutionModes(SPIRVForward *Forward) { ExecModes = std::move(Forward->ExecModes); } // Assume BB contains valid Id. SPIRVBasicBlock *addBasicBlock(SPIRVBasicBlock *BB) { Module->add(BB); BB->setParent(this); BBVec.push_back(BB); return BB; } _SPIRV_DCL_DEC void validate()const { SPIRVValue::validate(); IGC_ASSERT(FuncType && "Invalid func type"); } private: SPIRVFunctionParameter *addArgument(unsigned TheArgNo, SPIRVId TheId) { SPIRVFunctionParameter *Arg = new SPIRVFunctionParameter( getFunctionType()->getParameterType(TheArgNo), TheId, this, TheArgNo); Module->add(Arg); Parameters.push_back(Arg); return Arg; } void addAllArguments(SPIRVId FirstArgId) { for (size_t i = 0, e = getFunctionType()->getNumParameters(); i != e; ++i) addArgument(i, FirstArgId + i); } void decodeBB(SPIRVDecoder &); SPIRVTypeFunction *FuncType; // Function type SPIRVWord FCtrlMask; // Function control mask std::vector Parameters; typedef std::vector SPIRVLBasicBlockVector; SPIRVLBasicBlockVector BBVec; }; typedef SPIRVEntryOpCodeOnly SPIRVFunctionEnd; } #endif /* SPIRVFUNCTION_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVInstruction.cpp000066400000000000000000000211451363533017100277400ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVInstruction.cpp -Class to represent SPIR-V instruction - C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements SPIR-V instructions. /// //===----------------------------------------------------------------------===// #include "SPIRVInstruction.h" #include "SPIRVBasicBlock.h" #include "SPIRVFunction.h" #include "Probe.h" namespace spv { // Complete constructor for instruction with type and id SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB) :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType, TheId), BB(TheBB){ validate(); } SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheBM) : SPIRVValue(TheBM, TheWordCount, TheOC, TheType, TheId), BB(TheBB){ validate(); } // Complete constructor for instruction with id but no type SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVId TheId, SPIRVBasicBlock *TheBB) :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheId), BB(TheBB){ validate(); } // Complete constructor for instruction without type and id SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVBasicBlock *TheBB) :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC), BB(TheBB){ validate(); } // Complete constructor for instruction with type but no id SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVBasicBlock *TheBB) :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType), BB(TheBB){ validate(); } void SPIRVInstruction::setParent(SPIRVBasicBlock *TheBB) { IGC_ASSERT(TheBB && "Invalid BB"); if (BB == TheBB) return; IGC_ASSERT(BB == NULL && "BB cannot change parent"); BB = TheBB; } void SPIRVInstruction::setScope(SPIRVEntry *Scope) { IGC_ASSERT(Scope && Scope->getOpCode() == OpLabel && "Invalid scope"); setParent(static_cast(Scope)); } void SPIRVFunctionCall::validate()const { SPIRVFunctionCallGeneric::validate(); } SPIRVFunctionPointerCallINTEL::SPIRVFunctionPointerCallINTEL( SPIRVId TheId, SPIRVValue *TheCalledValue, SPIRVType *TheReturnType, const std::vector &TheArgs, SPIRVBasicBlock *BB) : SPIRVFunctionCallGeneric(TheReturnType, TheId, TheArgs, BB), CalledValueId(TheCalledValue->getId()) { validate(); } void SPIRVFunctionPointerCallINTEL::validate() const { SPIRVFunctionCallGeneric::validate(); } SPIRVFunctionPointerINTEL::SPIRVFunctionPointerINTEL(SPIRVId TheId, SPIRVType * TheType, SPIRVFunction * TheFunction, SPIRVBasicBlock * BB) : SPIRVInstruction(FixedWordCount, OC, TheType, TheId, BB), TheFunction(TheFunction->getId()) { validate(); } void SPIRVFunctionPointerINTEL::validate() const { SPIRVInstruction::validate(); } //Each instruction should implement this function std::vector SPIRVInstruction::getOperands() { std::vector Empty; IGC_ASSERT_EXIT(0 && "not supported"); return Empty; } std::vector SPIRVInstruction::getOperandTypes(const std::vector &Ops) { std::vector Tys; for (auto& I : Ops) { SPIRVType* Ty = nullptr; if (I->getOpCode() == OpFunction) Ty = reinterpret_cast(I)->getFunctionType(); else Ty = I->getType(); Tys.push_back(Ty); } return Tys; } std::vector SPIRVInstruction::getOperandTypes() { return getOperandTypes(getOperands()); } bool isSpecConstantOpAllowedOp(Op OC) { static SPIRVWord Table[] = { OpSConvert, OpFConvert, OpConvertFToS, OpConvertSToF, OpConvertFToU, OpConvertUToF, OpUConvert, OpConvertPtrToU, OpConvertUToPtr, OpGenericCastToPtr, OpPtrCastToGeneric, OpBitcast, OpQuantizeToF16, OpSNegate, OpNot, OpIAdd, OpISub, OpIMul, OpUDiv, OpSDiv, OpUMod, OpSRem, OpSMod, OpShiftRightLogical, OpShiftRightArithmetic, OpShiftLeftLogical, OpBitwiseOr, OpBitwiseXor, OpBitwiseAnd, OpFNegate, OpFAdd, OpFSub, OpFMul, OpFDiv, OpFRem, OpFMod, OpVectorShuffle, OpCompositeExtract, OpCompositeInsert, OpLogicalOr, OpLogicalAnd, OpLogicalNot, OpLogicalEqual, OpLogicalNotEqual, OpSelect, OpIEqual, OpULessThan, OpSLessThan, OpUGreaterThan, OpSGreaterThan, OpULessThanEqual, OpSLessThanEqual, OpUGreaterThanEqual, OpSGreaterThanEqual, OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain, OpInBoundsPtrAccessChain, }; static std::unordered_set Allow(std::begin(Table), std::end(Table)); return (Allow.count(OC) > 0); } SPIRVSpecConstantOp * createSpecConstantOpInst(SPIRVInstruction *Inst) { auto OC = Inst->getOpCode(); IGC_ASSERT(isSpecConstantOpAllowedOp(OC) && "Op code not allowed for OpSpecConstantOp"); auto Ops = Inst->getIds(Inst->getOperands()); Ops.insert(Ops.begin(), OC); return static_cast( SPIRVSpecConstantOp::create(OpSpecConstantOp, Inst->getType(), Inst->getId(), Ops, nullptr, Inst->getModule())); } SPIRVInstruction * createInstFromSpecConstantOp(SPIRVSpecConstantOp *Inst) { IGC_ASSERT(Inst->getOpCode() == OpSpecConstantOp && "Not OpSpecConstantOp"); auto Ops = Inst->getOpWords(); auto OC = static_cast(Ops[0]); IGC_ASSERT(isSpecConstantOpAllowedOp(OC) && "Op code not allowed for OpSpecConstantOp"); Ops.erase(Ops.begin(), Ops.begin() + 1); return SPIRVInstTemplateBase::create(OC, Inst->getType(), Inst->getId(), Ops, nullptr, Inst->getModule()); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVInstruction.h000066400000000000000000002137141363533017100274120ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVInstruction.h - Class to represent SPIRV instruction -*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines Instruction class for SPIR-V. /// //===----------------------------------------------------------------------===// #ifndef SPIRVINSTRUCTION_HPP_ #define SPIRVINSTRUCTION_HPP_ #include "SPIRVEnum.h" #include "SPIRVStream.h" #include "SPIRVValue.h" #include "SPIRVBasicBlock.h" #include "SPIRVFunction.h" #include "Probe.h" #include #include #include #include #include #include #include namespace spv{ typedef std::vector ValueVec; typedef std::pair ValueRange; class SPIRVBasicBlock; class SPIRVFunction; bool isSpecConstantOpAllowedOp(Op OC); class SPIRVComponentExecutionScope { public: SPIRVComponentExecutionScope(Scope TheScope = ScopeInvocation): ExecScope(TheScope){} Scope ExecScope; }; class SPIRVComponentMemorySemanticsMask { public: SPIRVComponentMemorySemanticsMask(SPIRVWord TheSema = SPIRVWORD_MAX): MemSema(TheSema){} SPIRVWord MemSema; }; class SPIRVComponentOperands { public: SPIRVComponentOperands(){}; SPIRVComponentOperands(const std::vector &TheOperands): Operands(TheOperands){}; SPIRVComponentOperands(std::vector &&TheOperands): Operands(std::move(TheOperands)){}; std::vector getCompOperands() { return Operands; } std::vector getCompOperandTypes() { std::vector Tys; for (auto &I:getCompOperands()) Tys.push_back(I->getType()); return Tys; } protected: std::vector Operands; }; class SPIRVInstruction: public SPIRVValue { protected: // Complete constructor for instruction with type and id SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB); // Complete constructor for instruction with module, type and id SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheBM); // Complete constructor for instruction with id but no type SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVId TheId, SPIRVBasicBlock *TheBB); // Complete constructor for instruction without type and id SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVBasicBlock *TheBB); // Complete constructor for instruction with type but no id SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVBasicBlock *TheBB); // Incomplete constructor SPIRVInstruction(Op TheOC) : SPIRVValue(TheOC), BB(NULL) {} public: virtual bool isInst() const { return true; } SPIRVBasicBlock *getParent() const {return BB;} SPIRVInstruction *getPrevious() const { return BB->getPrevious(this);} SPIRVInstruction *getNext() const { return BB->getNext(this);} virtual std::vector getOperands(); std::vector getOperandTypes(); static std::vector getOperandTypes( const std::vector &Ops); void setParent(SPIRVBasicBlock *); void setScope(SPIRVEntry *); void addFPRoundingMode(SPIRVFPRoundingModeKind Kind) { addDecorate(DecorationFPRoundingMode, Kind); } void eraseFPRoundingMode() { eraseDecorate(DecorationFPRoundingMode); } void setSaturatedConversion(bool Enable) { if (Enable) addDecorate(DecorationSaturatedConversion); else eraseDecorate(DecorationSaturatedConversion); } bool hasFPRoundingMode(SPIRVFPRoundingModeKind *Kind = nullptr) { SPIRVWord V; auto Found = hasDecorate(DecorationFPRoundingMode, 0, &V); if (Found && Kind) *Kind = static_cast(V); return Found; } bool isSaturatedConversion() { return hasDecorate(DecorationSaturatedConversion) || OpCode == OpSatConvertSToU || OpCode == OpSatConvertUToS; } SPIRVBasicBlock* getBasicBlock() const { return BB; } void setBasicBlock(SPIRVBasicBlock* TheBB) { BB = TheBB; if (TheBB) setModule(TheBB->getModule()); } virtual bool isOperandLiteral(unsigned Index) const { IGC_ASSERT(0 && "not implemented"); return false; } protected: void validate()const { SPIRVValue::validate(); } private: SPIRVBasicBlock *BB; }; class SPIRVInstTemplateBase:public SPIRVInstruction { public: /// Create an empty instruction. Mainly for getting format information, /// e.g. whether an operand is literal. static SPIRVInstTemplateBase *create(Op TheOC){ auto Inst = static_cast(SPIRVEntry::create(TheOC)); Inst->init(); return Inst; } /// Create a instruction without operands. static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheModule){ auto Inst = create(TheOC); Inst->init(TheType, TheId, TheBB, TheModule); return Inst; } /// Create a complete and valid instruction. static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType, SPIRVId TheId, const std::vector &TheOps, SPIRVBasicBlock *TheBB, SPIRVModule *TheModule){ auto Inst = create(TheOC); Inst->init(TheType, TheId, TheBB, TheModule); Inst->setOpWords(TheOps); Inst->validate(); return Inst; } SPIRVInstTemplateBase(Op OC = OpNop) :SPIRVInstruction(OC), HasVariWC(false){ init(); } virtual ~SPIRVInstTemplateBase(){} SPIRVInstTemplateBase *init(SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheModule){ IGC_ASSERT((TheBB || TheModule) && "Invalid BB or Module"); if (TheBB) setBasicBlock(TheBB); else { setModule(TheModule); } setId(hasId() ? TheId : SPIRVID_INVALID); setType(hasType() ? TheType : nullptr); return this; } virtual void init() {} virtual void initImpl(Op OC, bool HasId = true, SPIRVWord WC = 0, bool VariWC = false, unsigned Lit1 = ~0U, unsigned Lit2 = ~0U, unsigned Lit3 = ~0U){ OpCode = OC; if (!HasId) { setHasNoId(); setHasNoType(); } if (WC) SPIRVEntry::setWordCount(WC); setHasVariableWordCount(VariWC); addLit(Lit1); addLit(Lit2); addLit(Lit3); } bool isOperandLiteral(unsigned I) const override { return (Lit.count(I) > 0); } void addLit(unsigned L) { if (L != ~0U) Lit.insert(L); } /// \return Expected number of operands. If the instruction has variable /// number of words, return the minimum. SPIRVWord getExpectedNumOperands() const { IGC_ASSERT(WordCount > 0 && "Word count not initialized"); auto Exp = WordCount - 1; if (hasId()) --Exp; if (hasType()) --Exp; return Exp; } virtual void setOpWordsAndValidate(const std::vector &TheOps) { setOpWords(TheOps); validate(); } virtual void setOpWords(const std::vector &TheOps) { SPIRVWord WC = TheOps.size() + 1; if (hasId()) ++WC; if (hasType()) ++WC; if (WordCount) { if (WordCount == WC) { // do nothing } else { IGC_ASSERT(HasVariWC && WC >= WordCount && "Invalid word count"); SPIRVEntry::setWordCount(WC); } } else SPIRVEntry::setWordCount(WC); Ops = TheOps; } virtual void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); auto NumOps = WordCount - 1; if (hasId()) --NumOps; if (hasType()) --NumOps; Ops.resize(NumOps); } std::vector &getOpWords() { return Ops; } const std::vector &getOpWords() const { return Ops; } SPIRVWord getOpWord(int I) const { return Ops[I]; } // Get operands which are values. // Drop execution scope and group operation literals. // Return other literals as uint32 constants. virtual std::vector getOperands() { std::vector VOps; for (size_t I = 0, E = Ops.size(); I != E; ++I) VOps.push_back(getOperand(I)); return VOps; } virtual SPIRVValue *getOperand(unsigned I) { return isOperandLiteral(I) ? Module->getLiteralAsConstant(Ops[I]) : getValue(Ops[I]); } bool hasExecScope() const { return spv::hasExecScope(OpCode); } bool hasGroupOperation() const { return spv::hasGroupOperation(OpCode); } SPIRVGroupOperationKind getGroupOperation() const { if (!hasGroupOperation()) return GroupOperationCount; return static_cast(Ops[1]); } Scope getExecutionScope() const { if(!hasExecScope()) return ScopeInvocation; return static_cast( static_cast(getValue(Ops[0]))->getZExtIntValue()); } bool hasVariableWordCount() const { return HasVariWC; } void setHasVariableWordCount(bool VariWC) { HasVariWC = VariWC; } protected: virtual void decode(std::istream &I) { auto D = getDecoder(I); if (hasType()) D >> Type; if (hasId()) D >> Id; D >> Ops; } std::vector Ops; bool HasVariWC; std::unordered_set Lit; // Literal operand index }; template class SPIRVInstTemplate:public BT { public: typedef BT BaseTy; SPIRVInstTemplate(){ init(); } virtual ~SPIRVInstTemplate(){} virtual void init() { this->initImpl(OC, HasId, WC, HasVariableWC, Literal1, Literal2, Literal3); } }; class SPIRVMemoryAccess { public: SPIRVMemoryAccess(const std::vector &TheMemoryAccess): Alignment(0), Volatile(0) { MemoryAccessUpdate(TheMemoryAccess); } SPIRVMemoryAccess() : Alignment(0), Volatile(0){} void MemoryAccessUpdate(const std::vector &MemoryAccess) { bool readAlignment = false; for (auto MAValue : MemoryAccess) { if (readAlignment) { Alignment = MAValue; readAlignment = false; continue; } Volatile |= MAValue & MemoryAccessVolatileMask; readAlignment = (MAValue & MemoryAccessAlignedMask) != 0; } IGC_ASSERT(!readAlignment && "MemoryAccess Alignment flag is not followed by value"); } SPIRVWord getVolatile() const { return Volatile; } SPIRVWord getAlignment() const { return Alignment; } protected: SPIRVWord Alignment; SPIRVWord Volatile; }; class SPIRVVariable : public SPIRVInstruction { public: // Incomplete constructor SPIRVVariable() :SPIRVInstruction(OpVariable), StorageClass(SPIRVStorageClassKind::StorageClassCount){} SPIRVStorageClassKind getStorageClass() const { return StorageClass; } SPIRVValue *getInitializer() const { if (Initializer.empty()) return nullptr; IGC_ASSERT_EXIT(Initializer.size() == 1); return getValue(Initializer[0]); } bool isConstant() const { return hasDecorate(DecorationConstant); } bool isBuiltin(SPIRVBuiltinVariableKind *BuiltinKind = nullptr) const { SPIRVWord Kind; bool Found = hasDecorate(DecorationBuiltIn, 0, &Kind); if (!Found) return false; if (BuiltinKind) *BuiltinKind = static_cast(Kind); return true; } void setBuiltin(SPIRVBuiltinVariableKind Kind) { IGC_ASSERT(isValid(Kind)); addDecorate(new SPIRVDecorate(DecorationBuiltIn, this, Kind)); } void setIsConstant(bool Is) { if (Is) addDecorate(new SPIRVDecorate(DecorationConstant, this)); else eraseDecorate(DecorationConstant); } protected: void validate() const { SPIRVValue::validate(); IGC_ASSERT(isValid(StorageClass)); IGC_ASSERT(Initializer.size() == 1 || Initializer.empty()); } void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); Initializer.resize(WordCount - 4); } _SPIRV_DEF_DEC4(Type, Id, StorageClass, Initializer) SPIRVStorageClassKind StorageClass; std::vector Initializer; }; class SPIRVStore:public SPIRVInstruction, public SPIRVMemoryAccess { public: const static SPIRVWord FixedWords = 3; // Incomplete constructor SPIRVStore():SPIRVInstruction(OpStore), SPIRVMemoryAccess(), PtrId(SPIRVID_INVALID), ValId(SPIRVID_INVALID){ setAttr(); } SPIRVValue *getSrc() const { return getValue(ValId);} SPIRVValue *getDst() const { return getValue(PtrId);} protected: void setAttr() { setHasNoType(); setHasNoId(); } void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); MemoryAccess.resize(TheWordCount - FixedWords); } void decode(std::istream &I) { getDecoder(I) >> PtrId >> ValId >> MemoryAccess; MemoryAccessUpdate(MemoryAccess); } void validate()const { SPIRVInstruction::validate(); if (getSrc()->isForward() || getDst()->isForward()) return; IGC_ASSERT(getValueType(PtrId)->getPointerElementType()->isTypeVoid() == getValueType(ValId)->isTypeVoid() && getValueType(PtrId)->getPointerElementType()->isTypeArray() == getValueType(ValId)->isTypeArray() && getValueType(PtrId)->getPointerElementType()->isTypeBool() == getValueType(ValId)->isTypeBool() && getValueType(PtrId)->getPointerElementType()->isTypeComposite() == getValueType(ValId)->isTypeComposite() && getValueType(PtrId)->getPointerElementType()->isTypeEvent() == getValueType(ValId)->isTypeEvent() && getValueType(PtrId)->getPointerElementType()->isTypeFloat(0) == getValueType(ValId)->isTypeFloat(0) && getValueType(PtrId)->getPointerElementType()->isTypeImage() == getValueType(ValId)->isTypeImage() && getValueType(PtrId)->getPointerElementType()->isTypeOCLImage() == getValueType(ValId)->isTypeOCLImage() && getValueType(PtrId)->getPointerElementType()->isTypePipe() == getValueType(ValId)->isTypePipe() && getValueType(PtrId)->getPointerElementType()->isTypeInt(0) == getValueType(ValId)->isTypeInt(0) && getValueType(PtrId)->getPointerElementType()->isTypeSampler() == getValueType(ValId)->isTypeSampler() && getValueType(PtrId)->getPointerElementType()->isTypeStruct() == getValueType(ValId)->isTypeStruct() && getValueType(PtrId)->getPointerElementType()->isTypeVector() == getValueType(ValId)->isTypeVector() && getValueType(PtrId)->getPointerElementType()->isTypeVectorInt() == getValueType(ValId)->isTypeVectorInt() && getValueType(PtrId)->getPointerElementType()->isTypeVectorFloat() == getValueType(ValId)->isTypeVectorFloat() && getValueType(PtrId)->getPointerElementType()->isTypeVectorBool() == getValueType(ValId)->isTypeVectorBool() && getValueType(PtrId)->getPointerElementType()->isTypeNamedBarrier() == getValueType(ValId)->isTypeNamedBarrier() && "Inconsistent operand types"); } private: std::vector MemoryAccess; SPIRVId PtrId; SPIRVId ValId; }; class SPIRVLoad:public SPIRVInstruction, public SPIRVMemoryAccess { public: const static SPIRVWord FixedWords = 4; // Incomplete constructor SPIRVLoad():SPIRVInstruction(OpLoad), SPIRVMemoryAccess(), PtrId(SPIRVID_INVALID){} SPIRVValue *getSrc() const { return Module->get(PtrId);} protected: void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); MemoryAccess.resize(TheWordCount - FixedWords); } void decode(std::istream &I) { getDecoder(I) >> Type >> Id >> PtrId >> MemoryAccess; MemoryAccessUpdate(MemoryAccess); } void validate()const { SPIRVInstruction::validate(); IGC_ASSERT((getValue(PtrId)->isForward() || Type == getValueType(PtrId)->getPointerElementType()) && "Inconsistent types"); } private: SPIRVId PtrId; std::vector MemoryAccess; }; class SPIRVBinary:public SPIRVInstTemplateBase { protected: void validate()const { SPIRVId Op1 = Ops[0]; SPIRVId Op2 = Ops[1]; SPIRVType *op1Ty, *op2Ty; SPIRVInstruction::validate(); if (getValue(Op1)->isForward() || getValue(Op2)->isForward()) return; if (getValueType(Op1)->isTypeVector()) { op1Ty = getValueType(Op1)->getVectorComponentType(); op2Ty = getValueType(Op2)->getVectorComponentType(); IGC_ASSERT(getValueType(Op1)->getVectorComponentCount() == getValueType(Op2)->getVectorComponentCount() && "Inconsistent Vector component width"); } else { op1Ty = getValueType(Op1); op2Ty = getValueType(Op2); } if (isBinaryOpCode(OpCode)) { IGC_ASSERT(getValueType(Op1)== getValueType(Op2) && "Invalid type for binary instruction"); IGC_ASSERT((op1Ty->isTypeInt() || op2Ty->isTypeFloat()) && "Invalid type for Binary instruction"); IGC_ASSERT((op1Ty->getBitWidth() == op2Ty->getBitWidth()) && "Inconsistent BitWidth"); } else if (isShiftOpCode(OpCode)) { IGC_ASSERT((op1Ty->isTypeInt() || op2Ty->isTypeInt()) && "Invalid type for shift instruction"); } else if (isLogicalOpCode(OpCode)) { IGC_ASSERT((op1Ty->isTypeBool() || op2Ty->isTypeBool()) && "Invalid type for logical instruction"); } else if (isBitwiseOpCode(OpCode)) { IGC_ASSERT((op1Ty->isTypeInt() || op2Ty->isTypeInt()) && "Invalid type for bitwise instruction"); IGC_ASSERT((op1Ty->getIntegerBitWidth() == op2Ty->getIntegerBitWidth()) && "Inconsistent BitWidth"); } else { IGC_ASSERT_EXIT(0 && "Invalid op code!"); } } }; template class SPIRVBinaryInst:public SPIRVInstTemplate { }; #define _SPIRV_OP(x) typedef SPIRVBinaryInst SPIRV##x; _SPIRV_OP(IAdd) _SPIRV_OP(FAdd) _SPIRV_OP(ISub) _SPIRV_OP(FSub) _SPIRV_OP(IMul) _SPIRV_OP(FMul) _SPIRV_OP(UDiv) _SPIRV_OP(SDiv) _SPIRV_OP(FDiv) _SPIRV_OP(SRem) _SPIRV_OP(SMod) _SPIRV_OP(FRem) _SPIRV_OP(FMod) _SPIRV_OP(UMod) _SPIRV_OP(ShiftLeftLogical) _SPIRV_OP(ShiftRightLogical) _SPIRV_OP(ShiftRightArithmetic) _SPIRV_OP(LogicalAnd) _SPIRV_OP(LogicalOr) _SPIRV_OP(LogicalEqual) _SPIRV_OP(LogicalNotEqual) _SPIRV_OP(BitwiseAnd) _SPIRV_OP(BitwiseOr) _SPIRV_OP(BitwiseXor) _SPIRV_OP(Dot) #undef _SPIRV_OP template class SPIRVInstNoOperand:public SPIRVInstruction { public: // Complete constructor SPIRVInstNoOperand(SPIRVBasicBlock *TheBB):SPIRVInstruction(1, TheOpCode, TheBB){ setAttr(); validate(); } // Incomplete constructor SPIRVInstNoOperand():SPIRVInstruction(TheOpCode){ setAttr(); } protected: void setAttr() { setHasNoId(); setHasNoType(); } _SPIRV_DEF_DEC0 }; typedef SPIRVInstNoOperand SPIRVReturn; class SPIRVReturnValue:public SPIRVInstruction { public: static const Op OC = OpReturnValue; // Incomplete constructor SPIRVReturnValue():SPIRVInstruction(OC), ReturnValueId(SPIRVID_INVALID) { setAttr(); } SPIRVValue *getReturnValue() const { return getValue(ReturnValueId); } protected: void setAttr() { setHasNoId(); setHasNoType(); } _SPIRV_DEF_DEC1(ReturnValueId) void validate()const { SPIRVInstruction::validate(); } SPIRVId ReturnValueId; }; class SPIRVBranch:public SPIRVInstruction { public: static const Op OC = OpBranch; // Incomplete constructor SPIRVBranch():SPIRVInstruction(OC), TargetLabelId(SPIRVID_INVALID) { setHasNoId(); setHasNoType(); } SPIRVValue *getTargetLabel() const { return getValue(TargetLabelId); } protected: _SPIRV_DEF_DEC1(TargetLabelId) void validate()const { SPIRVInstruction::validate(); IGC_ASSERT(WordCount == 2); IGC_ASSERT(OpCode == OC); IGC_ASSERT(getTargetLabel()->isLabel() || getTargetLabel()->isForward()); } SPIRVId TargetLabelId; }; class SPIRVBranchConditional:public SPIRVInstruction { public: static const Op OC = OpBranchConditional; // Incomplete constructor SPIRVBranchConditional():SPIRVInstruction(OC), ConditionId(SPIRVID_INVALID), TrueLabelId(SPIRVID_INVALID), FalseLabelId(SPIRVID_INVALID) { setHasNoId(); setHasNoType(); } SPIRVValue *getCondition() const { return getValue(ConditionId); } SPIRVLabel *getTrueLabel() const { return SPIRVEntry::get(TrueLabelId); } SPIRVLabel *getFalseLabel() const { return SPIRVEntry::get(FalseLabelId); } protected: void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); BranchWeights.resize(TheWordCount - 4); } _SPIRV_DEF_DEC4(ConditionId, TrueLabelId, FalseLabelId, BranchWeights) void validate()const { SPIRVInstruction::validate(); IGC_ASSERT(WordCount == 4 || WordCount == 6); IGC_ASSERT(WordCount == BranchWeights.size() + 4); IGC_ASSERT(OpCode == OC); IGC_ASSERT(getCondition()->isForward() || getCondition()->getType()->isTypeBool()); IGC_ASSERT(getTrueLabel()->isForward() || getTrueLabel()->isLabel()); IGC_ASSERT(getFalseLabel()->isForward() || getFalseLabel()->isLabel()); } SPIRVId ConditionId; SPIRVId TrueLabelId; SPIRVId FalseLabelId; std::vector BranchWeights; }; class SPIRVPhi: public SPIRVInstruction { public: static const Op OC = OpPhi; static const SPIRVWord FixedWordCount = 3; SPIRVPhi():SPIRVInstruction(OC) {} std::vector getPairs() { return getValues(Pairs); } void addPair(SPIRVValue *Value, SPIRVBasicBlock *BB) { Pairs.push_back(Value->getId()); Pairs.push_back(BB->getId()); WordCount = Pairs.size() + FixedWordCount; validate(); } void setPairs(const std::vector &ThePairs) { Pairs = getIds(ThePairs); WordCount = Pairs.size() + FixedWordCount; validate(); } void foreachPair(std::function Func) { for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { SPIRVEntry *Value, *BB; if (!Module->exist(Pairs[2*I], &Value) || !Module->exist(Pairs[2*I+1], &BB)) continue; Func(static_cast(Value), static_cast(BB), I); } } void foreachPair(std::function Func) const { for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { SPIRVEntry *Value, *BB; if (!Module->exist(Pairs[2*I], &Value) || !Module->exist(Pairs[2*I+1], &BB)) continue; Func(static_cast(Value), static_cast(BB)); } } void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); Pairs.resize(TheWordCount - FixedWordCount); } _SPIRV_DEF_DEC3(Type, Id, Pairs) void validate()const { IGC_ASSERT(WordCount == Pairs.size() + FixedWordCount); IGC_ASSERT(OpCode == OC); IGC_ASSERT(Pairs.size() % 2 == 0); foreachPair([=](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB){ IGC_ASSERT(IncomingV->isForward() || IncomingV->getType() == Type); IGC_ASSERT(IncomingBB->isBasicBlock() || IncomingBB->isForward()); }); SPIRVInstruction::validate(); } protected: std::vector Pairs; }; class SPIRVCompare:public SPIRVInstTemplateBase { protected: void validate()const { auto Op1 = Ops[0]; auto Op2 = Ops[1]; SPIRVType *op1Ty, *op2Ty, *resTy; SPIRVInstruction::validate(); if (getValue(Op1)->isForward() || getValue(Op2)->isForward()) return; if (getValueType(Op1)->isTypeVector()) { op1Ty = getValueType(Op1)->getVectorComponentType(); op2Ty = getValueType(Op2)->getVectorComponentType(); resTy = Type->getVectorComponentType(); IGC_ASSERT(getValueType(Op1)->getVectorComponentCount() == getValueType(Op2)->getVectorComponentCount() && "Inconsistent Vector component width"); } else { op1Ty = getValueType(Op1); op2Ty = getValueType(Op2); resTy = Type; } IGC_ASSERT(isCmpOpCode(OpCode) && "Invalid op code for cmp inst"); IGC_ASSERT((resTy->isTypeBool() || resTy->isTypeInt()) && "Invalid type for compare instruction"); IGC_ASSERT(op1Ty == op2Ty && "Inconsistent types"); } }; template class SPIRVCmpInst:public SPIRVInstTemplate { }; #define _SPIRV_OP(x) typedef SPIRVCmpInst SPIRV##x; _SPIRV_OP(IEqual) _SPIRV_OP(FOrdEqual) _SPIRV_OP(FUnordEqual) _SPIRV_OP(INotEqual) _SPIRV_OP(FOrdNotEqual) _SPIRV_OP(FUnordNotEqual) _SPIRV_OP(ULessThan) _SPIRV_OP(SLessThan) _SPIRV_OP(FOrdLessThan) _SPIRV_OP(FUnordLessThan) _SPIRV_OP(UGreaterThan) _SPIRV_OP(SGreaterThan) _SPIRV_OP(FOrdGreaterThan) _SPIRV_OP(FUnordGreaterThan) _SPIRV_OP(ULessThanEqual) _SPIRV_OP(SLessThanEqual) _SPIRV_OP(FOrdLessThanEqual) _SPIRV_OP(FUnordLessThanEqual) _SPIRV_OP(UGreaterThanEqual) _SPIRV_OP(SGreaterThanEqual) _SPIRV_OP(FOrdGreaterThanEqual) _SPIRV_OP(FUnordGreaterThanEqual) _SPIRV_OP(LessOrGreater) _SPIRV_OP(Ordered) _SPIRV_OP(Unordered) #undef _SPIRV_OP class SPIRVSelect:public SPIRVInstruction { public: // Incomplete constructor SPIRVSelect():SPIRVInstruction(OpSelect), Condition(SPIRVID_INVALID), Op1(SPIRVID_INVALID), Op2(SPIRVID_INVALID){} SPIRVValue *getCondition() { return getValue(Condition);} SPIRVValue *getTrueValue() { return getValue(Op1);} SPIRVValue *getFalseValue() { return getValue(Op2);} protected: _SPIRV_DEF_DEC5(Type, Id, Condition, Op1, Op2) void validate()const { SPIRVInstruction::validate(); if (getValue(Condition)->isForward() || getValue(Op1)->isForward() || getValue(Op2)->isForward()) return; SPIRVType *conTy = getValueType(Condition)->isTypeVector() ? getValueType(Condition)->getVectorComponentType() : getValueType(Condition); IGC_ASSERT(conTy->isTypeBool() && "Invalid type"); IGC_ASSERT(getType() == getValueType(Op1) && getType() == getValueType(Op2) && "Inconsistent type"); } SPIRVId Condition; SPIRVId Op1; SPIRVId Op2; }; class SPIRVLoopMerge : public SPIRVInstruction { public: static const Op OC = OpLoopMerge; static const SPIRVWord FixedWordCount = 4; SPIRVLoopMerge(SPIRVId TheMergeBlock, SPIRVId TheContinueTarget, SPIRVWord TheLoopControl, std::vector TheLoopControlParameters, SPIRVBasicBlock *BB) : SPIRVInstruction(FixedWordCount + TheLoopControlParameters.size(), OC, BB), MergeBlock(TheMergeBlock), ContinueTarget(TheContinueTarget), LoopControl(TheLoopControl), LoopControlParameters(TheLoopControlParameters) { validate(); IGC_ASSERT(BB && "Invalid BB"); } SPIRVLoopMerge() : SPIRVInstruction(OC), MergeBlock(SPIRVID_MAX), LoopControl(SPIRVWORD_MAX) { setHasNoId(); setHasNoType(); } SPIRVId getMergeBlock() { return MergeBlock; } SPIRVId getContinueTarget() { return ContinueTarget; } SPIRVWord getLoopControl() { return LoopControl; } std::vector getLoopControlParameters() { return LoopControlParameters; } void setWordCount(SPIRVWord TheWordCount) override { SPIRVEntry::setWordCount(TheWordCount); LoopControlParameters.resize(TheWordCount - FixedWordCount); } _SPIRV_DEF_DEC4_OVERRIDE(MergeBlock, ContinueTarget, LoopControl, LoopControlParameters) protected: SPIRVId MergeBlock; SPIRVId ContinueTarget; SPIRVWord LoopControl; std::vector LoopControlParameters; }; class SPIRVSwitch: public SPIRVInstruction { public: static const Op OC = OpSwitch; static const SPIRVWord FixedWordCount = 3; typedef std::vector LiteralTy; typedef std::pair PairTy; SPIRVSwitch():SPIRVInstruction(OC), Select(SPIRVWORD_MAX), Default(SPIRVWORD_MAX) { setHasNoId(); setHasNoType(); } std::vector getPairs() { return getValues(Pairs); } SPIRVValue *getSelect() const { return getValue(Select);} SPIRVBasicBlock *getDefault() const { return static_cast(getValue(Default)); } size_t getNumPairs() const { return Pairs.size()/getPairSize();} size_t getLiteralsCount() const { return std::max(getSelect()->getType()->getBitWidth(), (uint32_t)32) / (sizeof(SPIRVWord) * 8); } size_t getPairSize() const { return getLiteralsCount() + 1; } void foreachPair(std::function Func) const { unsigned PairSize = getPairSize(); for (size_t I = 0, E = getNumPairs(); I != E; ++I) { SPIRVEntry *BB; LiteralTy Literals; if (!Module->exist(Pairs[PairSize*I + getLiteralsCount()], &BB)) continue; for (unsigned i = 0; i < getLiteralsCount(); ++i) { Literals.push_back(Pairs.at(PairSize*I + i)); } Func(Literals, static_cast(BB)); } } void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); Pairs.resize(TheWordCount - FixedWordCount); } _SPIRV_DEF_DEC3(Select, Default, Pairs) void validate()const { IGC_ASSERT(WordCount == Pairs.size() + FixedWordCount); IGC_ASSERT(OpCode == OC); IGC_ASSERT(getPairSize() > 1); IGC_ASSERT(Pairs.size() % getPairSize() == 0); foreachPair([=](LiteralTy Literals, SPIRVBasicBlock *BB){ IGC_ASSERT(BB->isBasicBlock() || BB->isForward()); }); SPIRVInstruction::validate(); } protected: SPIRVId Select; SPIRVId Default; std::vector Pairs; }; class SPIRVUnary:public SPIRVInstTemplateBase { protected: void validate()const { auto Op = Ops[0]; SPIRVInstruction::validate(); if (getValue(Op)->isForward()) return; if (isGenericNegateOpCode(OpCode)) { SPIRVType *resTy = Type->isTypeVector() ? Type->getVectorComponentType() : Type; SPIRVType *opTy = Type->isTypeVector() ? getValueType(Op)->getVectorComponentType() : getValueType(Op); IGC_ASSERT(getType() == getValueType(Op) && "Inconsistent type"); IGC_ASSERT((resTy->isTypeInt() || resTy->isTypeFloat()) && "Invalid type for Generic Negate instruction"); IGC_ASSERT((resTy->getBitWidth() == opTy->getBitWidth()) && "Invalid bitwidth for Generic Negate instruction"); IGC_ASSERT((Type->isTypeVector() ? (Type->getVectorComponentCount() == getValueType(Op)->getVectorComponentCount()): 1) && "Invalid vector component Width for Generic Negate instruction"); } } }; template class SPIRVUnaryInst:public SPIRVInstTemplate { }; #define _SPIRV_OP(x) typedef SPIRVUnaryInst SPIRV##x; _SPIRV_OP(ConvertFToU) _SPIRV_OP(ConvertFToS) _SPIRV_OP(ConvertSToF) _SPIRV_OP(ConvertUToF) _SPIRV_OP(UConvert) _SPIRV_OP(SConvert) _SPIRV_OP(FConvert) _SPIRV_OP(SatConvertSToU) _SPIRV_OP(SatConvertUToS) _SPIRV_OP(ConvertPtrToU) _SPIRV_OP(ConvertUToPtr) _SPIRV_OP(PtrCastToGeneric) _SPIRV_OP(GenericCastToPtr) _SPIRV_OP(Bitcast) _SPIRV_OP(SNegate) _SPIRV_OP(FNegate) _SPIRV_OP(Not) _SPIRV_OP(LogicalNot) _SPIRV_OP(IsNan) _SPIRV_OP(IsInf) _SPIRV_OP(IsFinite) _SPIRV_OP(IsNormal) _SPIRV_OP(SignBitSet) _SPIRV_OP(Any) _SPIRV_OP(All) #undef _SPIRV_OP class SPIRVAccessChainBase :public SPIRVInstTemplateBase { public: SPIRVValue *getBase() { return this->getValue(this->Ops[0]);} std::vector getIndices()const { std::vector IndexWords(this->Ops.begin() + 1, this->Ops.end()); return this->getValues(IndexWords); } bool isInBounds() { return OpCode == OpInBoundsAccessChain || OpCode == OpInBoundsPtrAccessChain; } bool hasPtrIndex() { return OpCode == OpPtrAccessChain || OpCode == OpInBoundsPtrAccessChain; } }; template class SPIRVAccessChainGeneric :public SPIRVInstTemplate { }; typedef SPIRVAccessChainGeneric SPIRVAccessChain; typedef SPIRVAccessChainGeneric SPIRVInBoundsAccessChain; typedef SPIRVAccessChainGeneric SPIRVPtrAccessChain; typedef SPIRVAccessChainGeneric SPIRVInBoundsPtrAccessChain; template class SPIRVFunctionCallGeneric: public SPIRVInstruction { public: SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId, const std::vector &TheArgs, SPIRVBasicBlock *BB) : SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB), Args(TheArgs) { SPIRVFunctionCallGeneric::validate(); IGC_ASSERT(BB && "Invalid BB"); } SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId, const std::vector &TheArgs, SPIRVBasicBlock *BB) : SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB) { Args = getIds(TheArgs); SPIRVFunctionCallGeneric::validate(); IGC_ASSERT(BB && "Invalid BB"); } SPIRVFunctionCallGeneric(SPIRVModule *BM, SPIRVWord ResId, SPIRVType *TheType, const std::vector &TheArgs) : SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, ResId, NULL, BM), Args(TheArgs) {} SPIRVFunctionCallGeneric():SPIRVInstruction(OC) {} const std::vector &getArguments() { return Args; } std::vector getArgumentValues() { return getValues(Args); } std::vector getArgumentValueTypes()const { std::vector ArgTypes; for (auto &I:Args) ArgTypes.push_back(getValue(I)->getType()); return ArgTypes; } void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); Args.resize(TheWordCount - FixedWordCount); } void validate()const { SPIRVInstruction::validate(); } protected: std::vector Args; }; class SPIRVFunctionCall: public SPIRVFunctionCallGeneric { public: SPIRVFunctionCall():FunctionId(SPIRVID_INVALID) {} SPIRVFunction *getFunction()const { return SPIRVEntry::get(FunctionId); } _SPIRV_DEF_DEC4(Type, Id, FunctionId, Args) void validate()const; bool isOperandLiteral(unsigned Index) const { return false;} protected: SPIRVId FunctionId; }; class SPIRVFunctionPointerCallINTEL : public SPIRVFunctionCallGeneric { public: SPIRVFunctionPointerCallINTEL(SPIRVId TheId, SPIRVValue* TheCalledValue, SPIRVType* TheReturnType, const std::vector& TheArgs, SPIRVBasicBlock* BB); SPIRVFunctionPointerCallINTEL() : CalledValueId(SPIRVID_INVALID) {} SPIRVValue* getCalledValue() const { return SPIRVEntry::get(CalledValueId); } _SPIRV_DEF_DEC4_OVERRIDE(Type, Id, CalledValueId, Args) void validate() const override; bool isOperandLiteral(unsigned Index) const { return false; } CapVec getRequiredCapability() const override { return getVec(CapabilityFunctionPointersINTEL); } protected: SPIRVId CalledValueId; }; class SPIRVFunctionPointerINTEL : public SPIRVInstruction { const static Op OC = OpFunctionPointerINTEL; const static SPIRVWord FixedWordCount = 4; public: SPIRVFunctionPointerINTEL(SPIRVId TheId, SPIRVType* TheType, SPIRVFunction* TheFunction, SPIRVBasicBlock* BB); SPIRVFunctionPointerINTEL() : SPIRVInstruction(OC), TheFunction(SPIRVID_INVALID) {} SPIRVFunction* getFunction() const { return SPIRVEntry::get(TheFunction); } _SPIRV_DEF_DEC3_OVERRIDE(Type, Id, TheFunction) void validate() const override; bool isOperandLiteral(unsigned Index) const { return false; } CapVec getRequiredCapability() const override { return getVec(CapabilityFunctionPointersINTEL); } protected: SPIRVId TheFunction; }; class SPIRVExtInst: public SPIRVFunctionCallGeneric { public: SPIRVExtInst(SPIRVExtInstSetKind SetKind = SPIRVEIS_Count, unsigned ExtOC = SPIRVWORD_MAX) :ExtSetId(SPIRVWORD_MAX), ExtOp(ExtOC), ExtSetKind(SetKind) {} void setExtSetId(unsigned Set) { ExtSetId = Set;} void setExtOp(unsigned ExtOC) { ExtOp = ExtOC;} SPIRVId getExtSetId()const { return ExtSetId; } SPIRVWord getExtOp()const { return ExtOp; } void setExtSetKindById() { IGC_ASSERT(Module && "Invalid module"); ExtSetKind = Module->getBuiltinSet(ExtSetId); IGC_ASSERT((ExtSetKind == SPIRVEIS_OpenCL || ExtSetKind == SPIRVEIS_DebugInfo) && "not supported"); } void decode(std::istream &I) { getDecoder(I) >> Type >> Id >> ExtSetId; setExtSetKindById(); switch(ExtSetKind) { case SPIRVEIS_OpenCL: getDecoder(I) >> ExtOpOCL; break; case SPIRVEIS_DebugInfo: getDecoder(I) >> ExtOpDbgInfo; break; default: IGC_ASSERT_EXIT(0 && "not supported"); getDecoder(I) >> ExtOp; break; } getDecoder(I) >> Args; } void validate()const { SPIRVFunctionCallGeneric::validate(); validateBuiltin(ExtSetId, ExtOp); } bool isOperandLiteral(unsigned Index) const { IGC_ASSERT(ExtSetKind == SPIRVEIS_OpenCL && "Unsupported extended instruction set"); auto EOC = static_cast(ExtOp); switch(EOC) { default: return false; case OpenCLLIB::vloadn: case OpenCLLIB::vload_halfn: case OpenCLLIB::vloada_halfn: return Index == 2; case OpenCLLIB::vstore_half_r: case OpenCLLIB::vstore_halfn_r: case OpenCLLIB::vstorea_halfn_r: return Index == 3; } } SPIRVExtInstSetKind getExtSetKind() { return ExtSetKind; } bool hasNoScope() { if (getExtSetKind() == SPIRVExtInstSetKind::SPIRVEIS_DebugInfo && ExtOpDbgInfo != OCLExtOpDbgKind::DbgDcl && ExtOpDbgInfo != OCLExtOpDbgKind::DbgVal) return true; else return false; } bool isScope() { return startsScope() || endsScope(); } bool startsScope() { if (getExtSetKind() == SPIRVExtInstSetKind::SPIRVEIS_DebugInfo && ExtOpDbgInfo == OCLExtOpDbgKind::Scope) return true; return false; } bool endsScope() { if (getExtSetKind() == SPIRVExtInstSetKind::SPIRVEIS_DebugInfo && ExtOpDbgInfo == OCLExtOpDbgKind::NoScope) return true; return false; } protected: SPIRVId ExtSetId; union { SPIRVWord ExtOp; OCLExtOpKind ExtOpOCL; OCLExtOpDbgKind ExtOpDbgInfo; }; SPIRVExtInstSetKind ExtSetKind; }; class SPIRVCompositeExtract:public SPIRVInstruction { public: const static Op OC = OpCompositeExtract; // Incomplete constructor SPIRVCompositeExtract():SPIRVInstruction(OC), Composite(SPIRVID_INVALID){} SPIRVValue *getComposite() { return getValue(Composite);} const std::vector& getIndices()const { return Indices;} protected: void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); Indices.resize(TheWordCount - 4); } _SPIRV_DEF_DEC4(Type, Id, Composite, Indices) // ToDo: validate the result type is consistent with the base type and indices // need to trace through the base type for struct types void validate()const { SPIRVInstruction::validate(); IGC_ASSERT(getValueType(Composite)->isTypeArray() || getValueType(Composite)->isTypeStruct() || getValueType(Composite)->isTypeVector()); } SPIRVId Composite; std::vector Indices; }; class SPIRVCompositeInsert:public SPIRVInstruction { public: const static Op OC = OpCompositeInsert; const static SPIRVWord FixedWordCount = 5; // Incomplete constructor SPIRVCompositeInsert():SPIRVInstruction(OC), Object(SPIRVID_INVALID), Composite(SPIRVID_INVALID){} SPIRVValue *getObject() { return getValue(Object);} SPIRVValue *getComposite() { return getValue(Composite);} const std::vector& getIndices()const { return Indices;} protected: void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); Indices.resize(TheWordCount - FixedWordCount); } _SPIRV_DEF_DEC5(Type, Id, Object, Composite, Indices) // ToDo: validate the object type is consistent with the base type and indices // need to trace through the base type for struct types void validate()const { SPIRVInstruction::validate(); IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == Indices.size() + FixedWordCount); IGC_ASSERT(getValueType(Composite)->isTypeArray() || getValueType(Composite)->isTypeStruct() || getValueType(Composite)->isTypeVector()); IGC_ASSERT(Type == getValueType(Composite)); } SPIRVId Object; SPIRVId Composite; std::vector Indices; }; class SPIRVCompositeConstruct: public SPIRVInstruction { public: // Complete constructor for composite construct const static Op OC = OpCompositeConstruct; // Default constructor SPIRVCompositeConstruct():SPIRVInstruction( OpCompositeConstruct ){} std::vector getElements()const { return getValues( Elements ); } protected: void validate() const { SPIRVValue::validate(); for(auto &I : Elements) getValue( I )->validate(); } void setWordCount( SPIRVWord WordCount ) { Elements.resize( WordCount - 3 ); } _SPIRV_DEF_DEC3( Type,Id,Elements ) std::vector Elements; }; class SPIRVCopyMemory :public SPIRVInstruction, public SPIRVMemoryAccess { public: const static Op OC = OpCopyMemory; const static SPIRVWord FixedWords = 3; // Incomplete constructor SPIRVCopyMemory() :SPIRVInstruction(OC), SPIRVMemoryAccess(), Target(SPIRVID_INVALID), Source(SPIRVID_INVALID) { setHasNoId(); setHasNoType(); } SPIRVValue *getSource() { return getValue(Source); } SPIRVValue *getTarget() { return getValue(Target); } protected: void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); MemoryAccess.resize(TheWordCount - FixedWords); } void decode(std::istream &I) { getDecoder(I) >> Target >> Source >> MemoryAccess; MemoryAccessUpdate(MemoryAccess); } void validate()const { IGC_ASSERT((getValueType(Id) == getValueType(Source)) && "Inconsistent type"); IGC_ASSERT(getValueType(Id)->isTypePointer() && "Invalid type"); IGC_ASSERT(!(getValueType(Id)->getPointerElementType()->isTypeVoid()) && "Invalid type"); SPIRVInstruction::validate(); } std::vector MemoryAccess; SPIRVId Target; SPIRVId Source; }; class SPIRVCopyMemorySized :public SPIRVInstruction, public SPIRVMemoryAccess { public: const static Op OC = OpCopyMemorySized; const static SPIRVWord FixedWords = 4; // Incomplete constructor SPIRVCopyMemorySized() :SPIRVInstruction(OC), SPIRVMemoryAccess(), Target(SPIRVID_INVALID), Source(SPIRVID_INVALID), Size(0) { setHasNoId(); setHasNoType(); } SPIRVValue *getSource() { return getValue(Source); } SPIRVValue *getTarget() { return getValue(Target); } SPIRVValue *getSize() { return getValue(Size); } protected: void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); MemoryAccess.resize(TheWordCount - FixedWords); } void decode(std::istream &I) { getDecoder(I) >> Target >> Source >> Size >> MemoryAccess; MemoryAccessUpdate(MemoryAccess); } void validate()const { SPIRVInstruction::validate(); } std::vector MemoryAccess; SPIRVId Target; SPIRVId Source; SPIRVId Size; }; class SPIRVVectorExtractDynamic:public SPIRVInstruction { public: const static Op OC = OpVectorExtractDynamic; // Incomplete constructor SPIRVVectorExtractDynamic():SPIRVInstruction(OC), VectorId(SPIRVID_INVALID), IndexId(SPIRVID_INVALID){} SPIRVValue *getVector() { return getValue(VectorId);} SPIRVValue *getIndex()const { return getValue(IndexId);} protected: _SPIRV_DEF_DEC4(Type, Id, VectorId, IndexId) void validate()const { SPIRVInstruction::validate(); if (getValue(VectorId)->isForward()) return; IGC_ASSERT(getValueType(VectorId)->isTypeVector()); } SPIRVId VectorId; SPIRVId IndexId; }; class SPIRVVectorInsertDynamic :public SPIRVInstruction { public: const static Op OC = OpVectorInsertDynamic; // Incomplete constructor SPIRVVectorInsertDynamic() :SPIRVInstruction(OC), VectorId(SPIRVID_INVALID), IndexId(SPIRVID_INVALID), ComponentId(SPIRVID_INVALID){} SPIRVValue *getVector() { return getValue(VectorId); } SPIRVValue *getIndex()const { return getValue(IndexId); } SPIRVValue *getComponent() { return getValue(ComponentId); } protected: _SPIRV_DEF_DEC5(Type, Id, VectorId, ComponentId, IndexId) void validate()const { SPIRVInstruction::validate(); if (getValue(VectorId)->isForward()) return; IGC_ASSERT(getValueType(VectorId)->isTypeVector()); } SPIRVId VectorId; SPIRVId IndexId; SPIRVId ComponentId; }; class SPIRVVectorShuffle:public SPIRVInstruction { public: const static Op OC = OpVectorShuffle; const static SPIRVWord FixedWordCount = 5; // Incomplete constructor SPIRVVectorShuffle():SPIRVInstruction(OC), Vector1(SPIRVID_INVALID), Vector2(SPIRVID_INVALID){} SPIRVValue *getVector1() { return getValue(Vector1);} SPIRVValue *getVector2() { return getValue(Vector2);} const std::vector& getComponents()const { return Components;} protected: void setWordCount(SPIRVWord TheWordCount) { SPIRVEntry::setWordCount(TheWordCount); Components.resize(TheWordCount - FixedWordCount); } _SPIRV_DEF_DEC5(Type, Id, Vector1, Vector2, Components) void validate()const { SPIRVInstruction::validate(); IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == Components.size() + FixedWordCount); IGC_ASSERT(Type->isTypeVector()); IGC_ASSERT(Type->getVectorComponentType() == getValueType(Vector1)->getVectorComponentType()); if (getValue(Vector1)->isForward() || getValue(Vector2)->isForward()) return; IGC_ASSERT(getValueType(Vector1) == getValueType(Vector2)); size_t CompCount = Type->getVectorComponentCount(); IGC_ASSERT(Components.size() == CompCount); IGC_ASSERT(Components.size() > 1); } SPIRVId Vector1; SPIRVId Vector2; std::vector Components; }; class SPIRVGroupAsyncCopy:public SPIRVInstruction { public: static const Op OC = OpGroupAsyncCopy; static const SPIRVWord WC = 9; // Incomplete constructor SPIRVGroupAsyncCopy():SPIRVInstruction(OC), ExecScope(ScopeInvocation), Destination(SPIRVID_INVALID), Source(SPIRVID_INVALID), NumElements(SPIRVID_INVALID), Stride(SPIRVID_INVALID), Event(SPIRVID_INVALID){ } Scope getExecScope() const { return ExecScope; } SPIRVValue *getDestination()const { return getValue(Destination);} SPIRVValue *getSource()const { return getValue(Source);} SPIRVValue *getNumElements()const { return getValue(NumElements);} SPIRVValue *getStride()const { return getValue(Stride);} SPIRVValue *getEvent()const { return getValue(Event);} std::vector getOperands() { std::vector Operands; Operands.push_back(ExecScope); Operands.push_back(Destination); Operands.push_back(Source); Operands.push_back(NumElements); Operands.push_back(Stride); Operands.push_back(Event); return getValues(Operands); } protected: _SPIRV_DEF_DEC8(Type, Id, ExecScope, Destination, Source, NumElements, Stride, Event) void validate()const { IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == WC); SPIRVInstruction::validate(); isValid(ExecScope); } Scope ExecScope; SPIRVId Destination; SPIRVId Source; SPIRVId NumElements; SPIRVId Stride; SPIRVId Event; }; enum SPIRVOpKind { SPIRVOPK_Id, SPIRVOPK_Literal, SPIRVOPK_Count }; class SPIRVDevEnqInstBase:public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityDeviceEnqueue); } }; class SPIRVSubgroupDispatchInstBase:public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilitySubgroupDispatch); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // CL 2.0 enqueue kernel builtins _SPIRV_OP(EnqueueMarker, true, 7) _SPIRV_OP(EnqueueKernel, true, 13, true) _SPIRV_OP(GetKernelNDrangeSubGroupCount, true, 8) _SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, true, 8) _SPIRV_OP(GetKernelWorkGroupSize, true, 7) _SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, true, 7) _SPIRV_OP(RetainEvent, false, 2) _SPIRV_OP(ReleaseEvent, false, 2) _SPIRV_OP(CreateUserEvent, true, 3) _SPIRV_OP(IsValidEvent, true, 4) _SPIRV_OP(SetUserEventStatus, false, 3) _SPIRV_OP(CaptureEventProfilingInfo, false, 4) _SPIRV_OP(GetDefaultQueue, true, 3) _SPIRV_OP(BuildNDRange, true, 6) #undef _SPIRV_OP // Subgroup Dispatch opcodes #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; _SPIRV_OP(GetKernelLocalSizeForSubgroupCount, true, 8) _SPIRV_OP(GetKernelMaxNumSubgroups, true, 7) #undef _SPIRV_OP class SPIRVPipeInstBase:public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityPipes); } }; class SPIRVPipeStorageInstBase : public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityPipeStorage); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // CL 2.0 pipe builtins _SPIRV_OP(ReadPipe, true, 7) _SPIRV_OP(WritePipe, true, 7) _SPIRV_OP(ReservedReadPipe, true, 9) _SPIRV_OP(ReservedWritePipe, true, 9) _SPIRV_OP(ReserveReadPipePackets, true, 7) _SPIRV_OP(ReserveWritePipePackets, true, 7) _SPIRV_OP(CommitReadPipe, false, 5) _SPIRV_OP(CommitWritePipe, false, 5) _SPIRV_OP(IsValidReserveId, true, 4) _SPIRV_OP(GetNumPipePackets, true, 6) _SPIRV_OP(GetMaxPipePackets, true, 6) #undef _SPIRV_OP #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Pipe storage builtins _SPIRV_OP(CreatePipeFromPipeStorage, true, 4) #undef _SPIRV_OP class SPIRVGroupInstBase:public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityGroups); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Group instructions _SPIRV_OP(GroupWaitEvents, false, 4) _SPIRV_OP(GroupAll, true, 5) _SPIRV_OP(GroupAny, true, 5) _SPIRV_OP(GroupBroadcast, true, 6) _SPIRV_OP(GroupIAdd, true, 6, false, 1) _SPIRV_OP(GroupFAdd, true, 6, false, 1) _SPIRV_OP(GroupFMin, true, 6, false, 1) _SPIRV_OP(GroupUMin, true, 6, false, 1) _SPIRV_OP(GroupSMin, true, 6, false, 1) _SPIRV_OP(GroupFMax, true, 6, false, 1) _SPIRV_OP(GroupUMax, true, 6, false, 1) _SPIRV_OP(GroupSMax, true, 6, false, 1) _SPIRV_OP(GroupReserveReadPipePackets, true, 8) _SPIRV_OP(GroupReserveWritePipePackets, true, 8) _SPIRV_OP(GroupCommitReadPipe, false, 6) _SPIRV_OP(GroupCommitWritePipe, false, 6) #undef _SPIRV_OP class SPIRVGroupNonUniformInstBase :public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityNonUniform); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Non uniform group instructions _SPIRV_OP(GroupNonUniformElect, true, 4) #undef _SPIRV_OP class SPIRVGroupNonUniformVoteInstBase :public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityNonUniformVote); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Non uniform vote group instructions _SPIRV_OP(GroupNonUniformAll, true, 5) _SPIRV_OP(GroupNonUniformAny, true, 5) _SPIRV_OP(GroupNonUniformAllEqual, true, 5) #undef _SPIRV_OP class SPIRVGroupNonUniformBallotInstBase :public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityNonUniformBallot); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Non uniform ballot group instructions _SPIRV_OP(GroupNonUniformBroadcast, true, 6) _SPIRV_OP(GroupNonUniformBroadcastFirst, true, 5) _SPIRV_OP(GroupNonUniformBallot, true, 5) _SPIRV_OP(GroupNonUniformInverseBallot, true, 5) _SPIRV_OP(GroupNonUniformBallotBitExtract, true, 6) _SPIRV_OP(GroupNonUniformBallotBitCount, true, 6) _SPIRV_OP(GroupNonUniformBallotFindLSB, true, 5) _SPIRV_OP(GroupNonUniformBallotFindMSB, true, 5) #undef _SPIRV_OP class SPIRVGroupNonUniformArithmeticInstBase :public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityNonUniformArithmetic); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Non uniform ballot group instructions _SPIRV_OP(GroupNonUniformIAdd, true, 6, true, 1) // TODO: handle optional ClusterSize _SPIRV_OP(GroupNonUniformFAdd, true, 6, true, 1) _SPIRV_OP(GroupNonUniformIMul, true, 6, true, 1) _SPIRV_OP(GroupNonUniformFMul, true, 6, true, 1) _SPIRV_OP(GroupNonUniformSMin, true, 6, true, 1) _SPIRV_OP(GroupNonUniformUMin, true, 6, true, 1) _SPIRV_OP(GroupNonUniformFMin, true, 6, true, 1) _SPIRV_OP(GroupNonUniformSMax, true, 6, true, 1) _SPIRV_OP(GroupNonUniformUMax, true, 6, true, 1) _SPIRV_OP(GroupNonUniformFMax, true, 6, true, 1) _SPIRV_OP(GroupNonUniformBitwiseAnd, true, 6, true, 1) _SPIRV_OP(GroupNonUniformBitwiseOr, true, 6, true, 1) _SPIRV_OP(GroupNonUniformBitwiseXor, true, 6, true, 1) _SPIRV_OP(GroupNonUniformLogicalAnd, true, 6, true, 1) _SPIRV_OP(GroupNonUniformLogicalOr, true, 6, true, 1) _SPIRV_OP(GroupNonUniformLogicalXor, true, 6, true, 1) #undef _SPIRV_OP class SPIRVGroupNonUniformShuffleInstBase :public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityNonUniformShuffle); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Non uniform shuffle group instructions _SPIRV_OP(GroupNonUniformShuffle, true, 6) _SPIRV_OP(GroupNonUniformShuffleXor, true, 6) #undef _SPIRV_OP class SPIRVGroupNonUniformShuffleRelativeInstBase :public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityNonUniformShuffle); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Non uniform shuffle relative group instructions _SPIRV_OP(GroupNonUniformShuffleUp, true, 6) _SPIRV_OP(GroupNonUniformShuffleDown, true, 6) #undef _SPIRV_OP class SPIRVAtomicInstBase:public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityInt64Atomics); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Atomic builtins _SPIRV_OP(AtomicFlagTestAndSet, true, 6) _SPIRV_OP(AtomicFlagClear, false, 4) _SPIRV_OP(AtomicLoad, true, 6) _SPIRV_OP(AtomicStore, false, 5) _SPIRV_OP(AtomicExchange, true, 7) _SPIRV_OP(AtomicCompareExchange, true, 9) _SPIRV_OP(AtomicCompareExchangeWeak, true, 9) _SPIRV_OP(AtomicIIncrement, true, 6) _SPIRV_OP(AtomicIDecrement, true, 6) _SPIRV_OP(AtomicIAdd, true, 7) _SPIRV_OP(AtomicISub, true, 7) _SPIRV_OP(AtomicUMin, true, 7) _SPIRV_OP(AtomicUMax, true, 7) _SPIRV_OP(AtomicSMin, true, 7) _SPIRV_OP(AtomicSMax, true, 7) _SPIRV_OP(AtomicAnd, true, 7) _SPIRV_OP(AtomicOr, true, 7) _SPIRV_OP(AtomicXor, true, 7) #undef _SPIRV_OP class SPIRVNamedBarrierInstBase :public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityNamedBarrier); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; _SPIRV_OP(NamedBarrierInitialize, true /*HasId*/, 4 /*WC*/, false /*VariWC*/) _SPIRV_OP(MemoryNamedBarrier, false /*HasId*/, 4 /*WC*/, false /*VariWC*/) #undef _SPIRV_OP #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; _SPIRV_OP(MemoryBarrier, false /*HasId*/, 3 /*WC*/, false /*VariWC*/) _SPIRV_OP(ControlBarrier, false /*HasId*/, 4 /*WC*/, false /*VariWC*/) _SPIRV_OP(UMulExtended, true, 5) _SPIRV_OP(SMulExtended, true, 5) _SPIRV_OP(BitReverse, true, 4) _SPIRV_OP(BitCount, true, 4) #undef _SPIRV_OP class SPIRVImageInstBase:public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilityImageBasic); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Image instructions _SPIRV_OP(SampledImage, true, 5) _SPIRV_OP(ImageSampleImplicitLod, true, 5, true) _SPIRV_OP(ImageSampleExplicitLod, true, 7, true, 2) _SPIRV_OP(ImageRead, true, 5, true, 2) _SPIRV_OP(ImageWrite, false, 4, true, 3) _SPIRV_OP(ImageQueryFormat, true, 4) _SPIRV_OP(ImageQueryOrder, true, 4) _SPIRV_OP(ImageQuerySizeLod, true, 5) _SPIRV_OP(ImageQuerySize, true, 4) _SPIRV_OP(ImageQueryLod, true, 5) _SPIRV_OP(ImageQueryLevels, true, 4) _SPIRV_OP(ImageQuerySamples, true, 4) #undef _SPIRV_OP #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Other instructions _SPIRV_OP(SpecConstantOp, true, 4, true) _SPIRV_OP(GenericPtrMemSemantics, true, 4, false) _SPIRV_OP(GenericCastToPtrExplicit, true, 5, false, 1) _SPIRV_OP(SizeOf, true, 4, false) _SPIRV_OP(CopyObject, true, 4, false) #undef _SPIRV_OP // Uncommon instructions #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; _SPIRV_OP(Unreachable, false, 1) _SPIRV_OP(LifetimeStart, false, 3) _SPIRV_OP(LifetimeStop, false, 3) _SPIRV_OP(SelectionMerge, false, 3) _SPIRV_OP(VectorTimesScalar, true, 5) _SPIRV_OP(ReadClockKHR, true, 4) #undef _SPIRV_OP class SPIRVBallotInstBase : public SPIRVInstTemplateBase { public: CapVec getRequiriedCapability() const { return getVec(SPIRVCapabilityKind::CapabilitySubgroupBallotKHR); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; _SPIRV_OP(SubgroupBallotKHR, true /*HasId*/, 4 /*WC*/, false /*VariWC*/) _SPIRV_OP(SubgroupFirstInvocationKHR, true /*HasId*/, 4 /*WC*/, false /*VariWC*/) #undef _SPIRV_OP class SPIRVSubgroupShuffleINTELInstBase : public SPIRVInstTemplateBase { protected: CapVec getRequiredCapability() const override { return getVec(CapabilitySubgroupShuffleINTEL); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Intel Subgroup Shuffle Instructions _SPIRV_OP(SubgroupShuffleINTEL, true, 5) _SPIRV_OP(SubgroupShuffleDownINTEL, true, 6) _SPIRV_OP(SubgroupShuffleUpINTEL, true, 6) _SPIRV_OP(SubgroupShuffleXorINTEL, true, 5) #undef _SPIRV_OP class SPIRVSubgroupBufferBlockIOINTELInstBase : public SPIRVInstTemplateBase { protected: CapVec getRequiredCapability() const override { return getVec(CapabilitySubgroupBufferBlockIOINTEL); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Intel Subgroup Buffer Block Read and Write Instructions _SPIRV_OP(SubgroupBlockReadINTEL, true, 4) _SPIRV_OP(SubgroupBlockWriteINTEL, false, 3) #undef _SPIRV_OP class SPIRVSubgroupImageBlockIOINTELInstBase : public SPIRVInstTemplateBase { protected: CapVec getRequiredCapability() const override { return getVec(CapabilitySubgroupImageBlockIOINTEL); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Intel Subgroup Image Block Read and Write Instructions _SPIRV_OP(SubgroupImageBlockReadINTEL, true, 5) _SPIRV_OP(SubgroupImageBlockWriteINTEL, false, 4) #undef _SPIRV_OP class SPIRVSubgroupImageMediaBlockIOINTELInstBase:public SPIRVInstTemplateBase { protected: CapVec getRequiredCapability() const override { return getVec(CapabilitySubgroupImageMediaBlockIOINTEL); } }; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate \ SPIRV##x; // Intel Subgroup Image Media Block Read and Write Instructions _SPIRV_OP(SubgroupImageMediaBlockReadINTEL, true, 7) _SPIRV_OP(SubgroupImageMediaBlockWriteINTEL, false, 6) #undef _SPIRV_OP class SPIRVSubgroupAVCIntelInstBase : public SPIRVInstTemplateBase { protected: CapVec getRequiredCapability() const override { return getVec(CapabilitySubgroupAvcMotionEstimationINTEL); } }; // Intel Subgroup AVC Motion Estimation Instructions typedef SPIRVInstTemplate< SPIRVSubgroupAVCIntelInstBase, OpVmeImageINTEL, true, 5> SPIRVVmeImageINTEL; #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate SPIRVSubgroupAvc##x##INTEL; _SPIRV_OP(MceGetDefaultInterBaseMultiReferencePenalty, true, 5) _SPIRV_OP(MceSetInterBaseMultiReferencePenalty, true, 5) _SPIRV_OP(MceGetDefaultInterShapePenalty, true, 5) _SPIRV_OP(MceSetInterShapePenalty, true, 5) _SPIRV_OP(MceGetDefaultInterDirectionPenalty, true, 5) _SPIRV_OP(MceSetInterDirectionPenalty, true, 5) _SPIRV_OP(MceGetDefaultInterMotionVectorCostTable, true, 5) _SPIRV_OP(MceGetDefaultHighPenaltyCostTable, true, 3) _SPIRV_OP(MceGetDefaultMediumPenaltyCostTable, true, 3) _SPIRV_OP(MceGetDefaultLowPenaltyCostTable, true, 3) _SPIRV_OP(MceSetMotionVectorCostFunction, true, 7) _SPIRV_OP(MceSetAcOnlyHaar, true, 4) _SPIRV_OP(MceSetSourceInterlacedFieldPolarity, true, 5) _SPIRV_OP(MceSetSingleReferenceInterlacedFieldPolarity, true, 5) _SPIRV_OP(MceSetDualReferenceInterlacedFieldPolarities, true, 6) _SPIRV_OP(MceConvertToImePayload, true, 4) _SPIRV_OP(MceConvertToImeResult, true, 4) _SPIRV_OP(MceConvertToRefPayload, true, 4) _SPIRV_OP(MceConvertToRefResult, true, 4) _SPIRV_OP(MceConvertToSicPayload, true, 4) _SPIRV_OP(MceConvertToSicResult, true, 4) _SPIRV_OP(MceGetMotionVectors, true, 4) _SPIRV_OP(MceGetInterDistortions, true, 4) _SPIRV_OP(MceGetBestInterDistortions, true, 4) _SPIRV_OP(MceGetInterMajorShape, true, 4) _SPIRV_OP(MceGetInterMinorShape, true, 4) _SPIRV_OP(MceGetInterDirections, true, 4) _SPIRV_OP(MceGetInterMotionVectorCount, true, 4) _SPIRV_OP(MceGetInterReferenceIds, true, 4) _SPIRV_OP(MceGetInterReferenceInterlacedFieldPolarities, true, 6) _SPIRV_OP(ImeInitialize, true, 6) _SPIRV_OP(ImeSetSingleReference, true, 6) _SPIRV_OP(ImeSetDualReference, true, 7) _SPIRV_OP(ImeRefWindowSize, true, 5) _SPIRV_OP(ImeAdjustRefOffset, true, 7) _SPIRV_OP(ImeConvertToMcePayload, true, 4) _SPIRV_OP(ImeSetMaxMotionVectorCount, true, 5) _SPIRV_OP(ImeSetUnidirectionalMixDisable, true, 4) _SPIRV_OP(ImeSetEarlySearchTerminationThreshold, true, 5) _SPIRV_OP(ImeSetWeightedSad, true, 5) _SPIRV_OP(ImeEvaluateWithSingleReference, true, 6) _SPIRV_OP(ImeEvaluateWithDualReference, true, 7) _SPIRV_OP(ImeEvaluateWithSingleReferenceStreamin, true, 7) _SPIRV_OP(ImeEvaluateWithDualReferenceStreamin, true, 8) _SPIRV_OP(ImeEvaluateWithSingleReferenceStreamout, true, 6) _SPIRV_OP(ImeEvaluateWithDualReferenceStreamout, true, 7) _SPIRV_OP(ImeEvaluateWithSingleReferenceStreaminout, true, 7) _SPIRV_OP(ImeEvaluateWithDualReferenceStreaminout, true, 8) _SPIRV_OP(ImeConvertToMceResult, true, 4) _SPIRV_OP(ImeGetSingleReferenceStreamin, true, 4) _SPIRV_OP(ImeGetDualReferenceStreamin, true, 4) _SPIRV_OP(ImeStripSingleReferenceStreamout, true, 4) _SPIRV_OP(ImeStripDualReferenceStreamout, true, 4) _SPIRV_OP(ImeGetStreamoutSingleReferenceMajorShapeMotionVectors, true, 5) _SPIRV_OP(ImeGetStreamoutSingleReferenceMajorShapeDistortions, true, 5) _SPIRV_OP(ImeGetStreamoutSingleReferenceMajorShapeReferenceIds, true, 5) _SPIRV_OP(ImeGetStreamoutDualReferenceMajorShapeMotionVectors, true, 6) _SPIRV_OP(ImeGetStreamoutDualReferenceMajorShapeDistortions, true, 6) _SPIRV_OP(ImeGetStreamoutDualReferenceMajorShapeReferenceIds, true, 6) _SPIRV_OP(ImeGetBorderReached, true, 5) _SPIRV_OP(ImeGetTruncatedSearchIndication, true, 4) _SPIRV_OP(ImeGetUnidirectionalEarlySearchTermination, true, 4) _SPIRV_OP(ImeGetWeightingPatternMinimumMotionVector, true, 4) _SPIRV_OP(ImeGetWeightingPatternMinimumDistortion, true, 4) _SPIRV_OP(FmeInitialize, true, 10) _SPIRV_OP(BmeInitialize, true, 11) _SPIRV_OP(RefConvertToMcePayload, true, 4) _SPIRV_OP(RefSetBidirectionalMixDisable, true, 4) _SPIRV_OP(RefSetBilinearFilterEnable, true, 4) _SPIRV_OP(RefEvaluateWithSingleReference, true, 6) _SPIRV_OP(RefEvaluateWithDualReference, true, 7) _SPIRV_OP(RefEvaluateWithMultiReference, true, 6) _SPIRV_OP(RefEvaluateWithMultiReferenceInterlaced, true, 7) _SPIRV_OP(RefConvertToMceResult, true, 4) _SPIRV_OP(SicInitialize, true, 4) _SPIRV_OP(SicConfigureSkc, true, 9) _SPIRV_OP(SicGetMotionVectorMask, true, 5) _SPIRV_OP(SicConvertToMcePayload, true, 4) _SPIRV_OP(SicSetIntraLumaShapePenalty, true, 5) _SPIRV_OP(SicSetBilinearFilterEnable, true, 4) _SPIRV_OP(SicSetSkcForwardTransformEnable, true, 5) _SPIRV_OP(SicSetBlockBasedRawSkipSad, true, 5) _SPIRV_OP(SicEvaluateWithSingleReference, true, 6) _SPIRV_OP(SicEvaluateWithDualReference, true, 7) _SPIRV_OP(SicEvaluateWithMultiReference, true, 6) _SPIRV_OP(SicEvaluateWithMultiReferenceInterlaced, true, 7) _SPIRV_OP(SicConvertToMceResult, true, 4) _SPIRV_OP(SicGetInterRawSads, true, 4) #undef _SPIRV_OP class SPIRVSubgroupAVCIntelInstBaseIntra : public SPIRVInstTemplateBase { protected: CapVec getRequiredCapability() const override { return getVec(CapabilitySubgroupAvcMotionEstimationIntraINTEL); } }; // Intel Subgroup AVC Motion Estimation Intra Instructions #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate SPIRVSubgroupAvc##x##INTEL; _SPIRV_OP(MceGetDefaultIntraLumaShapePenalty, true, 5) _SPIRV_OP(MceGetDefaultIntraLumaModePenalty, true, 5) _SPIRV_OP(MceGetDefaultNonDcLumaIntraPenalty, true, 3) _SPIRV_OP(SicConfigureIpeLuma, true, 11) _SPIRV_OP(SicSetIntraLumaModeCostFunction, true, 7) _SPIRV_OP(SicEvaluateIpe, true, 5) _SPIRV_OP(SicGetIpeLumaShape, true, 4) _SPIRV_OP(SicGetBestIpeLumaDistortion, true, 4) _SPIRV_OP(SicGetPackedIpeLumaModes, true, 4) _SPIRV_OP(SicGetPackedSkcLumaCountThreshold, true, 4) _SPIRV_OP(SicGetPackedSkcLumaSumThreshold, true, 4) #undef _SPIRV_OP class SPIRVSubgroupAVCIntelInstBaseChroma : public SPIRVInstTemplateBase { protected: CapVec getRequiredCapability() const override { return getVec(CapabilitySubgroupAvcMotionEstimationChromaINTEL); } }; // Intel Subgroup AVC Motion Estimation Chroma Instructions #define _SPIRV_OP(x, ...) \ typedef SPIRVInstTemplate SPIRVSubgroupAvc##x##INTEL; _SPIRV_OP(MceGetDefaultIntraChromaModeBasePenalty, true, 3) _SPIRV_OP(SicConfigureIpeLumaChroma, true, 14) _SPIRV_OP(SicSetIntraChromaModeCostFunction, true, 5) _SPIRV_OP(SicGetBestIpeChromaDistortion, true, 4) _SPIRV_OP(SicGetIpeChromaMode, true, 4) #undef _SPIRV_OP SPIRVSpecConstantOp *createSpecConstantOpInst(SPIRVInstruction *Inst); SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *C); } #endif // SPIRVINSTRUCTION_HPP_ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVModule.cpp000066400000000000000000000717421363533017100266540ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVModule.cpp - Class to represent SPIR-V module --------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements Module class for SPIR-V. /// //===----------------------------------------------------------------------===// #include "SPIRVModule.h" #include "SPIRVDebug.h" #include "SPIRVDecorate.h" #include "SPIRVEntry.h" #include "SPIRVValue.h" #include "SPIRVFunction.h" #include "SPIRVInstruction.h" #include "SPIRVAsm.h" #include "Probe.h" namespace spv{ SPIRVModule::SPIRVModule() {} SPIRVModule::~SPIRVModule() {} class SPIRVModuleImpl : public SPIRVModule { public: SPIRVModuleImpl():SPIRVModule(), NextId(0), SPIRVVersion(SPIRVVersionSupported::fullyCompliant), SPIRVGenerator(SPIRVGEN_AMDOpenSourceLLVMSPIRVTranslator), InstSchema(SPIRVISCH_Default), SrcLang(SpvSourceLanguageOpenCL_C), SrcLangVer(12), MemoryModel(SPIRVMemoryModelKind::MemoryModelOpenCL), SCMap(nullptr) { AddrModel = sizeof(size_t) == 32 ? AddressingModelPhysical32 : AddressingModelPhysical64; }; virtual ~SPIRVModuleImpl(); // Object query functions bool exist(SPIRVId) const override; bool exist(SPIRVId, SPIRVEntry **) const override; SPIRVId getId(SPIRVId Id = SPIRVID_INVALID, unsigned Increment = 1); virtual SPIRVEntry *getEntry(SPIRVId Id) const override; virtual void addUnknownStructField( SPIRVTypeStruct*, unsigned idx, SPIRVId id) override; virtual void resolveUnknownStructFields() override; bool hasDebugInfo() const override { return getCompilationUnit() != nullptr; } // Error handling functions SPIRVErrorLog &getErrorLog() override { return ErrLog;} SPIRVErrorCode getError(std::string &ErrMsg) override { return ErrLog.getError(ErrMsg);} // Module query functions SPIRVAddressingModelKind getAddressingModel() override { return AddrModel;} SPIRVExtInstSetKind getBuiltinSet(SPIRVId SetId) const override; const SPIRVCapSet &getCapability() const override { return CapSet;} bool isSpecConstantSpecialized(SPIRVWord spec_id) const override { if(SCMap) return SCMap->find(spec_id) != SCMap->end(); else return false; } uint64_t getSpecConstant(SPIRVWord spec_id) override { IGC_ASSERT_EXIT(isSpecConstantSpecialized(spec_id) && "Specialization constant was not specialized!"); return SCMap->at(spec_id); } void setSpecConstantMap(SPIRVSpecConstantMap *specConstants) override { SCMap = specConstants; } std::set &getExtension() override { return SPIRVExt;} SPIRVFunction *getFunction(unsigned I) const override { return FuncVec[I];} SPIRVAsmINTEL *getAsm(unsigned I) const override { return AsmVec[I]; } SPIRVVariable *getVariable(unsigned I) const override { return VariableVec[I];} virtual SPIRVValue *getValue(SPIRVId TheId) const override; virtual std::vector getValues(const std::vector&)const override; virtual std::vector getIds(const std::vector&)const override; virtual std::vector getIds(const std::vector&)const override; virtual SPIRVType *getValueType(SPIRVId TheId)const override; virtual std::vector getValueTypes(const std::vector&) const override; SPIRVMemoryModelKind getMemoryModel() override { return MemoryModel;} virtual SPIRVConstant* getLiteralAsConstant(unsigned Literal) override; unsigned getNumEntryPoints(SPIRVExecutionModelKind EM) const override{ auto Loc = EntryPointVec.find(EM); if (Loc == EntryPointVec.end()) return 0; return Loc->second.size(); } SPIRVFunction *getEntryPoint(SPIRVExecutionModelKind EM, unsigned I) const override { auto Loc = EntryPointVec.find(EM); if (Loc == EntryPointVec.end()) return nullptr; IGC_ASSERT_EXIT(I < Loc->second.size()); return get(Loc->second[I]); } unsigned getNumFunctions() const override { return FuncVec.size();} unsigned getNumVariables() const override { return VariableVec.size();} SpvSourceLanguage getSourceLanguage(SPIRVWord * Ver = nullptr) const override { if (Ver) *Ver = SrcLangVer; return SrcLang; } std::set &getSourceExtension() override { return SrcExtension;} bool isEntryPoint(SPIRVExecutionModelKind, SPIRVId EP) const override; const std::string &getModuleProcessed() const { return ModuleProcessed; } const std::vector &getStringVec() const override { return StringVec; } // Module changing functions bool importBuiltinSet(const std::string &, SPIRVId *) override; bool importBuiltinSetWithId(const std::string &, SPIRVId) override; void optimizeDecorates() override; void setAddressingModel(SPIRVAddressingModelKind AM) override { AddrModel = AM;} void setAlignment(SPIRVValue *, SPIRVWord) override; void setMemoryModel(SPIRVMemoryModelKind MM) override { MemoryModel = MM;} void setName(SPIRVEntry *E, const std::string &Name) override; void setSourceLanguage(SpvSourceLanguage Lang, SPIRVWord Ver) override { SrcLang = Lang; SrcLangVer = Ver; } void setModuleProcessed(const std::string& MP) override { ModuleProcessed = MP; } // Object creation functions template void addTo(std::vector &V, SPIRVEntry *E); virtual SPIRVEntry *addEntry(SPIRVEntry *E) override; virtual SPIRVString *getString(const std::string &Str) override; virtual SPIRVMemberName *addMemberName(SPIRVTypeStruct *ST, SPIRVWord MemberNumber, const std::string &Name) override; virtual SPIRVLine *addLine(SPIRVString *FileName, SPIRVWord Line, SPIRVWord Column) override; virtual void addCapability(SPIRVCapabilityKind) override; virtual const SPIRVDecorateGeneric *addDecorate(const SPIRVDecorateGeneric *) override; virtual SPIRVDecorationGroup *addDecorationGroup() override; virtual SPIRVDecorationGroup *addDecorationGroup(SPIRVDecorationGroup *Group) override; virtual SPIRVGroupDecorate *addGroupDecorate(SPIRVDecorationGroup *Group, const std::vector &Targets) override; virtual SPIRVGroupDecorateGeneric *addGroupDecorateGeneric( SPIRVGroupDecorateGeneric *GDec) override; virtual SPIRVGroupMemberDecorate *addGroupMemberDecorate( SPIRVDecorationGroup *Group, const std::vector &Targets) override; virtual void addEntryPoint(SPIRVExecutionModelKind ExecModel, SPIRVId EntryPoint) override; virtual SPIRVForward *addForward(SPIRVType *Ty) override; virtual SPIRVForward *addForward(SPIRVId, SPIRVType *Ty) override; virtual SPIRVFunction *addFunction(SPIRVFunction *) override; virtual SPIRVFunction *addFunction(SPIRVTypeFunction *, SPIRVId) override; virtual SPIRVEntry *replaceForward(SPIRVForward *, SPIRVEntry *) override; // Type creation functions template T * addType(T *Ty); virtual SPIRVTypeInt *addIntegerType(unsigned BitWidth) override; // Constant creation functions virtual SPIRVValue *addConstant(SPIRVValue *) override; virtual SPIRVValue *addConstant(SPIRVType *, uint64_t) override; virtual SPIRVInstruction *addLoopMergeInst( SPIRVId MergeBlock, SPIRVId ContinueTarget, SPIRVWord LoopControl, std::vector LoopControlParameters, SPIRVBasicBlock *BB) override; // Instruction creation functions virtual SPIRVInstruction * addInstruction(SPIRVInstruction *Inst, SPIRVBasicBlock *BB, SPIRVInstruction *InsertBefore = nullptr); SPIRVEntry *addAsmTargetINTEL(const std::string &) override; SPIRVValue *addAsmINTEL(SPIRVTypeFunction *, SPIRVAsmTargetINTEL *, const std::string &, const std::string &) override; SPIRVInstruction *addAsmCallINTELInst(SPIRVAsmINTEL *, const std::vector &, SPIRVBasicBlock *) override; virtual SPIRVExtInst* getCompilationUnit() const override { for (auto& item : IdEntryMap) { if (item.second->getOpCode() == spv::Op::OpExtInst) { auto extInst = static_cast(item.second); if (extInst->getExtSetKind() == SPIRVExtInstSetKind::SPIRVEIS_DebugInfo && extInst->getExtOp() == OCLExtOpDbgKind::CompileUnit) return extInst; } } return nullptr; } virtual std::vector getGlobalVars() override { std::vector globalVars; for (auto& item : IdEntryMap) { if (item.second->getOpCode() == spv::Op::OpExtInst) { auto extInst = static_cast(item.second); if (extInst->getExtSetKind() == SPIRVExtInstSetKind::SPIRVEIS_DebugInfo && extInst->getExtOp() == OCLExtOpDbgKind::GlobalVariable) globalVars.push_back(extInst); } } return globalVars; } virtual std::vector parseSpecConstants() override { std::vector specConstants; for (auto& item : IdEntryMap) { Op opcode = item.second->getOpCode(); if (opcode == spv::Op::OpSpecConstant || opcode == spv::Op::OpSpecConstantTrue || opcode == spv::Op::OpSpecConstantFalse) { auto specConstant = static_cast(item.second); specConstants.push_back(specConstant); } } return specConstants; } // I/O functions friend std::istream & operator>>(std::istream &I, SPIRVModule& M); private: SPIRVErrorLog ErrLog; SPIRVId NextId; SPIRVWord SPIRVVersion; SPIRVGeneratorKind SPIRVGenerator; SPIRVInstructionSchemaKind InstSchema; SpvSourceLanguage SrcLang; SPIRVWord SrcLangVer; std::set SrcExtension; std::set SPIRVExt; SPIRVAddressingModelKind AddrModel; SPIRVMemoryModelKind MemoryModel; std::string ModuleProcessed; typedef std::map SPIRVIdToEntryMap; typedef std::map > > SPIRVUnknownStructFieldMap; typedef std::unordered_set SPIRVEntrySet; typedef std::set SPIRVIdSet; typedef std::vector SPIRVIdVec; typedef std::vector SPIRVFunctionVector; typedef std::vector SPIRVVariableVec; typedef std::vector SPIRVStringVec; typedef std::vector SPIRVLineVec; typedef std::vector SPIRVDecGroupVec; typedef std::vector SPIRVGroupDecVec; typedef std::map SPIRVIdToBuiltinSetMap; typedef std::map SPIRVExecModelIdSetMap; typedef std::map SPIRVExecModelIdVecMap; typedef std::unordered_map SPIRVStringMap; typedef std::vector SPIRVAsmVector; SPIRVAsmVector AsmVec; SPIRVIdToEntryMap IdEntryMap; SPIRVUnknownStructFieldMap UnknownStructFieldMap; SPIRVFunctionVector FuncVec; SPIRVVariableVec VariableVec; SPIRVEntrySet EntryNoId; // Entries without id SPIRVIdToBuiltinSetMap IdBuiltinMap; SPIRVIdSet NamedId; SPIRVStringVec StringVec; SPIRVLineVec LineVec; SPIRVDecorateSet DecorateSet; SPIRVDecGroupVec DecGroupVec; SPIRVGroupDecVec GroupDecVec; SPIRVExecModelIdSetMap EntryPointSet; SPIRVExecModelIdVecMap EntryPointVec; SPIRVStringMap StrMap; SPIRVCapSet CapSet; SPIRVSpecConstantMap *SCMap; std::map IntTypeMap; std::map LiteralMap; void layoutEntry(SPIRVEntry* Entry); }; SPIRVModuleImpl::~SPIRVModuleImpl() { for (auto I : IdEntryMap) delete I.second; for (auto I : EntryNoId) delete I; } SPIRVLine* SPIRVModuleImpl::addLine(SPIRVString* FileName, SPIRVWord Line, SPIRVWord Column) { auto L = add(new SPIRVLine(this, FileName->getId(), Line, Column)); return L; } // Creates decoration group and group decorates from decorates shared by // multiple targets. void SPIRVModuleImpl::optimizeDecorates() { for (auto I = DecorateSet.begin(), E = DecorateSet.end(); I != E;) { auto D = *I; if (D->getOpCode() == OpMemberDecorate) { ++I; continue; } auto ER = DecorateSet.equal_range(D); if (std::distance(ER.first, ER.second) < 2) { I = ER.second; continue; } auto G = new SPIRVDecorationGroup(this, getId()); std::vector Targets; Targets.push_back(D->getTargetId()); const_cast(D)->setTargetId(G->getId()); G->getDecorations().insert(D); for (I = ER.first; I != ER.second; ++I) { auto E = *I; if (*E == *D) continue; Targets.push_back(E->getTargetId()); } DecorateSet.erase(ER.first, ER.second); auto GD = new SPIRVGroupDecorate(G, Targets); DecGroupVec.push_back(G); GroupDecVec.push_back(GD); } } void SPIRVModuleImpl::addCapability(SPIRVCapabilityKind Cap) { CapSet.insert(Cap); } SPIRVConstant* SPIRVModuleImpl::getLiteralAsConstant(unsigned Literal) { auto Loc = LiteralMap.find(Literal); if (Loc != LiteralMap.end()) return Loc->second; auto Ty = addIntegerType(32); auto V = new SPIRVConstant(this, Ty, getId(), static_cast(Literal)); LiteralMap[Literal] = V; addConstant(V); return V; } void SPIRVModuleImpl::layoutEntry(SPIRVEntry* E) { auto OC = E->getOpCode(); switch (OC) { case OpString: addTo(StringVec, E); break; case OpLine: addTo(LineVec, E); break; case OpVariable: { auto BV = static_cast(E); if (!BV->getParent()) addTo(VariableVec, E); } break; default: break; } } // Add an entry to the id to entry map. // Assert if the id is mapped to a different entry. // Certain entries need to be add to specific collectors to maintain // logic layout of SPIRV. SPIRVEntry * SPIRVModuleImpl::addEntry(SPIRVEntry *Entry) { IGC_ASSERT(Entry && "Invalid entry"); if (Entry->hasId()) { SPIRVId Id = Entry->getId(); IGC_ASSERT(Entry->getId() != SPIRVID_INVALID && "Invalid id"); SPIRVEntry *Mapped = nullptr; if (exist(Id, &Mapped)) { if (Mapped->getOpCode() == OpForward) { replaceForward(static_cast(Mapped), Entry); } else { IGC_ASSERT(Mapped == Entry && "Id used twice"); } } else { IdEntryMap[Id] = Entry; } } else { EntryNoId.insert(Entry); } Entry->setModule(this); layoutEntry(Entry); return Entry; } bool SPIRVModuleImpl::exist(SPIRVId Id) const { return exist(Id, nullptr); } bool SPIRVModuleImpl::exist(SPIRVId Id, SPIRVEntry **Entry) const { IGC_ASSERT(Id != SPIRVID_INVALID && "Invalid Id"); SPIRVIdToEntryMap::const_iterator Loc = IdEntryMap.find(Id); if (Loc == IdEntryMap.end()) return false; if (Entry) *Entry = Loc->second; return true; } // If Id is invalid, returns the next available id. // Otherwise returns the given id and adjust the next available id by increment. SPIRVId SPIRVModuleImpl::getId(SPIRVId Id, unsigned increment) { if (!isValid(Id)) Id = NextId; else NextId = std::max(Id, NextId); NextId += increment; return Id; } SPIRVEntry * SPIRVModuleImpl::getEntry(SPIRVId Id) const { IGC_ASSERT(Id != SPIRVID_INVALID && "Invalid Id"); SPIRVIdToEntryMap::const_iterator Loc = IdEntryMap.find(Id); IGC_ASSERT_EXIT(Loc != IdEntryMap.end() && "Id is not in map"); return Loc->second; } void SPIRVModuleImpl::addUnknownStructField( SPIRVTypeStruct* pStruct, unsigned idx, SPIRVId id) { UnknownStructFieldMap[pStruct].push_back(std::make_pair(idx, id)); } void SPIRVModuleImpl::resolveUnknownStructFields() { for (auto &kv : UnknownStructFieldMap) { auto *pStruct = kv.first; for (auto &indices : kv.second) { unsigned idx = indices.first; SPIRVId id = indices.second; auto *pTy = static_cast(getEntry(id)); pStruct->setMemberType(idx, pTy); } } UnknownStructFieldMap.clear(); } SPIRVExtInstSetKind SPIRVModuleImpl::getBuiltinSet(SPIRVId SetId) const { auto Loc = IdBuiltinMap.find(SetId); IGC_ASSERT_EXIT(Loc != IdBuiltinMap.end() && "Invalid builtin set id"); return Loc->second; } bool SPIRVModuleImpl::isEntryPoint(SPIRVExecutionModelKind ExecModel, SPIRVId EP) const { IGC_ASSERT(isValid(ExecModel) && "Invalid execution model"); IGC_ASSERT(EP != SPIRVID_INVALID && "Invalid function id"); auto Loc = EntryPointSet.find(ExecModel); if (Loc == EntryPointSet.end()) return false; return (Loc->second.count(EP) > 0); } // Module change functions bool SPIRVModuleImpl::importBuiltinSet(const std::string& BuiltinSetName, SPIRVId *BuiltinSetId) { SPIRVId TmpBuiltinSetId = getId(); if (!importBuiltinSetWithId(BuiltinSetName, TmpBuiltinSetId)) return false; if (BuiltinSetId) *BuiltinSetId = TmpBuiltinSetId; return true; } bool SPIRVModuleImpl::importBuiltinSetWithId(const std::string& BuiltinSetName, SPIRVId BuiltinSetId) { SPIRVExtInstSetKind BuiltinSet = SPIRVEIS_Count; SPIRVCKRT(SPIRVBuiltinSetNameMap::rfind(BuiltinSetName, &BuiltinSet), InvalidBuiltinSetName, "Actual is " + BuiltinSetName); IdBuiltinMap[BuiltinSetId] = BuiltinSet; return true; } void SPIRVModuleImpl::setAlignment(SPIRVValue *V, SPIRVWord A) { V->setAlignment(A); } void SPIRVModuleImpl::setName(SPIRVEntry *E, const std::string &Name) { E->setName(Name); if (!E->hasId()) return; if (!Name.empty()) NamedId.insert(E->getId()); else NamedId.erase(E->getId()); } // Type creation functions template T * SPIRVModuleImpl::addType(T *Ty) { add(Ty); if (!Ty->getName().empty()) setName(Ty, Ty->getName()); return Ty; } SPIRVTypeInt * SPIRVModuleImpl::addIntegerType(unsigned BitWidth) { auto Loc = IntTypeMap.find(BitWidth); if (Loc != IntTypeMap.end()) return Loc->second; auto Ty = new SPIRVTypeInt(this, getId(), BitWidth, false); IntTypeMap[BitWidth] = Ty; return addType(Ty); } SPIRVFunction * SPIRVModuleImpl::addFunction(SPIRVFunction *Func) { FuncVec.push_back(add(Func)); return Func; } SPIRVFunction * SPIRVModuleImpl::addFunction(SPIRVTypeFunction *FuncType, SPIRVId Id) { return addFunction(new SPIRVFunction(this, FuncType, getId(Id, FuncType->getNumParameters() + 1))); } const SPIRVDecorateGeneric * SPIRVModuleImpl::addDecorate(const SPIRVDecorateGeneric *Dec) { SPIRVId Id = Dec->getTargetId(); SPIRVEntry *Target = nullptr; bool Found = exist(Id, &Target); IGC_ASSERT(Found && "Decorate target does not exist"); if (!Dec->getOwner()) DecorateSet.insert(Dec); return Dec; } void SPIRVModuleImpl::addEntryPoint(SPIRVExecutionModelKind ExecModel, SPIRVId EntryPoint){ IGC_ASSERT(isValid(ExecModel) && "Invalid execution model"); IGC_ASSERT(EntryPoint != SPIRVID_INVALID && "Invalid entry point"); EntryPointSet[ExecModel].insert(EntryPoint); EntryPointVec[ExecModel].push_back(EntryPoint); } SPIRVForward * SPIRVModuleImpl::addForward(SPIRVType *Ty) { return add(new SPIRVForward(this, Ty, getId())); } SPIRVForward * SPIRVModuleImpl::addForward(SPIRVId Id, SPIRVType *Ty) { return add(new SPIRVForward(this, Ty, Id)); } SPIRVEntry * SPIRVModuleImpl::replaceForward(SPIRVForward *Forward, SPIRVEntry *Entry) { SPIRVId Id = Entry->getId(); SPIRVId ForwardId = Forward->getId(); if (ForwardId == Id) IdEntryMap[Id] = Entry; else { auto Loc = IdEntryMap.find(Id); IGC_ASSERT_EXIT(Loc != IdEntryMap.end()); IdEntryMap.erase(Loc); Entry->setId(ForwardId); IdEntryMap[ForwardId] = Entry; } // Annotations include name, decorations, execution modes Entry->takeAnnotations(Forward); delete Forward; return Entry; } SPIRVValue * SPIRVModuleImpl::addConstant(SPIRVValue *C) { return add(C); } SPIRVValue * SPIRVModuleImpl::addConstant(SPIRVType *Ty, uint64_t V) { if (Ty->isTypeBool()) { if (V) return new SPIRVConstantTrue(this, Ty, getId()); else return new SPIRVConstantFalse(this, Ty, getId()); } return addConstant(new SPIRVConstant(this, Ty, getId(), V)); } // Instruction creation functions SPIRVInstruction * SPIRVModuleImpl::addInstruction(SPIRVInstruction *Inst, SPIRVBasicBlock *BB, SPIRVInstruction *InsertBefore) { if (BB) return BB->addInstruction(Inst, InsertBefore); if (Inst->getOpCode() != OpSpecConstantOp) Inst = createSpecConstantOpInst(Inst); return static_cast(addConstant(Inst)); } SPIRVEntry *SPIRVModuleImpl::addAsmTargetINTEL(const std::string &TheTarget) { auto Asm = new SPIRVAsmTargetINTEL(this, getId(), TheTarget); return add(Asm); } SPIRVValue *SPIRVModuleImpl::addAsmINTEL(SPIRVTypeFunction *TheType, SPIRVAsmTargetINTEL *TheTarget, const std::string &TheInstructions, const std::string &TheConstraints) { auto Asm = new SPIRVAsmINTEL(this, TheType, getId(), TheTarget, TheInstructions, TheConstraints); AsmVec.push_back(Asm); return add(Asm); } SPIRVInstruction * SPIRVModuleImpl::addAsmCallINTELInst(SPIRVAsmINTEL *TheAsm, const std::vector &TheArguments, SPIRVBasicBlock *BB) { return addInstruction( new SPIRVAsmCallINTEL(getId(), TheAsm, TheArguments, BB), BB); } SPIRVInstruction *SPIRVModuleImpl::addLoopMergeInst( SPIRVId MergeBlock, SPIRVId ContinueTarget, SPIRVWord LoopControl, std::vector LoopControlParameters, SPIRVBasicBlock *BB) { return addInstruction( new SPIRVLoopMerge(MergeBlock, ContinueTarget, LoopControl, LoopControlParameters, BB), BB, const_cast(BB->getTerminateInstr())); } template void SPIRVModuleImpl::addTo(std::vector& V, SPIRVEntry* E) { V.push_back(static_cast(E)); } // The first decoration group includes all the previously defined decorates. // The second decoration group includes all the decorates defined between the // first and second decoration group. So long so forth. SPIRVDecorationGroup* SPIRVModuleImpl::addDecorationGroup() { return addDecorationGroup(new SPIRVDecorationGroup(this, getId())); } SPIRVDecorationGroup* SPIRVModuleImpl::addDecorationGroup(SPIRVDecorationGroup* Group) { add(Group); Group->takeDecorates(DecorateSet); DecGroupVec.push_back(Group); IGC_ASSERT(DecorateSet.empty()); return Group; } SPIRVGroupDecorateGeneric* SPIRVModuleImpl::addGroupDecorateGeneric(SPIRVGroupDecorateGeneric *GDec) { add(GDec); GDec->decorateTargets(); GroupDecVec.push_back(GDec); return GDec; } SPIRVGroupDecorate* SPIRVModuleImpl::addGroupDecorate( SPIRVDecorationGroup* Group, const std::vector& Targets) { auto GD = new SPIRVGroupDecorate(Group, getIds(Targets)); addGroupDecorateGeneric(GD); return GD; } SPIRVGroupMemberDecorate* SPIRVModuleImpl::addGroupMemberDecorate( SPIRVDecorationGroup* Group, const std::vector& Targets) { auto GMD = new SPIRVGroupMemberDecorate(Group, getIds(Targets)); addGroupDecorateGeneric(GMD); return GMD; } SPIRVString* SPIRVModuleImpl::getString(const std::string& Str) { auto Loc = StrMap.find(Str); if (Loc != StrMap.end()) return Loc->second; auto S = add(new SPIRVString(this, getId(), Str)); StrMap[Str] = S; return S; } SPIRVMemberName* SPIRVModuleImpl::addMemberName(SPIRVTypeStruct* ST, SPIRVWord MemberNumber, const std::string& Name) { return add(new SPIRVMemberName(ST, MemberNumber, Name)); } std::istream & operator>> (std::istream &I, SPIRVModule &M) { SPIRVDecoder Decoder(I, M); SPIRVModuleImpl &MI = *static_cast(&M); SPIRVWord Magic; Decoder >> Magic; IGC_ASSERT_EXIT((MagicNumber == Magic) && "Invalid magic number"); Decoder >> MI.SPIRVVersion; bool supportVersion = MI.SPIRVVersion <= SPIRVVersionSupported::fullyCompliant; IGC_ASSERT_EXIT(supportVersion && "Unsupported SPIRV version number"); Decoder >> MI.SPIRVGenerator; // Bound for Id Decoder >> MI.NextId; Decoder >> MI.InstSchema; IGC_ASSERT(MI.InstSchema == SPIRVISCH_Default && "Unsupported instruction schema"); while(Decoder.getWordCountAndOpCode()) Decoder.getEntry(); MI.optimizeDecorates(); return I; } SPIRVModule * SPIRVModule::createSPIRVModule() { return new SPIRVModuleImpl; } SPIRVValue * SPIRVModuleImpl::getValue(SPIRVId TheId)const { return get(TheId); } SPIRVType * SPIRVModuleImpl::getValueType(SPIRVId TheId)const { return get(TheId)->getType(); } std::vector SPIRVModuleImpl::getValues(const std::vector& IdVec)const { std::vector ValueVec; for (auto i:IdVec) ValueVec.push_back(getValue(i)); return ValueVec; } std::vector SPIRVModuleImpl::getValueTypes(const std::vector& IdVec)const { std::vector TypeVec; for (auto i:IdVec) TypeVec.push_back(getValue(i)->getType()); return TypeVec; } std::vector SPIRVModuleImpl::getIds(const std::vector &ValueVec)const { std::vector IdVec; for (auto i:ValueVec) IdVec.push_back(i->getId()); return IdVec; } std::vector SPIRVModuleImpl::getIds(const std::vector &ValueVec)const { std::vector IdVec; for (auto i:ValueVec) IdVec.push_back(i->getId()); return IdVec; } SPIRVDbgInfo::SPIRVDbgInfo(SPIRVModule *TM) :M(TM){ } std::string SPIRVDbgInfo::getEntryPointFileStr(SPIRVExecutionModelKind EM, unsigned I) { if (M->getNumEntryPoints(EM) == 0) return ""; return getFunctionFileStr(M->getEntryPoint(EM, I)); } std::string SPIRVDbgInfo::getFunctionFileStr(SPIRVFunction *F) { if (F->hasLine()) return F->getLine()->getFileNameStr(); return ""; } unsigned SPIRVDbgInfo::getFunctionLineNo(SPIRVFunction *F) { if (F->hasLine()) return F->getLine()->getLine(); return 0; } bool IsSPIRVBinary(const std::string &Img) { if (Img.size() < sizeof(unsigned)) return false; auto Magic = reinterpret_cast(Img.data()); return *Magic == MagicNumber; } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVModule.h000066400000000000000000000245051363533017100263140ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVModule.h - Class to represent a SPIR-V module --------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines Module class for SPIR-V. /// //===----------------------------------------------------------------------===// #ifndef SPIRVMODULE_HPP_ #define SPIRVMODULE_HPP_ #include "SPIRVEntry.h" #include #include #include #include #include #include namespace spv{ class SPIRVBasicBlock; class SPIRVEntry; class SPIRVFunction; class SPIRVInstruction; class SPIRVType; class SPIRVTypeArray; class SPIRVTypeBool; class SPIRVTypeFloat; class SPIRVTypeFunction; class SPIRVTypeInt; class SPIRVTypeOpaque; class SPIRVTypePointer; class SPIRVTypeImage; class SPIRVTypeSampler; class SPIRVTypeSampledImage; class SPIRVTypeStruct; class SPIRVTypeVector; class SPIRVTypeVoid; class SPIRVTypePipe; class SPIRVTypeNamedBarrier; class SPIRVValue; class SPIRVVariable; class SPIRVDecorateGeneric; class SPIRVDecorationGroup; class SPIRVGroupDecorate; class SPIRVGroupMemberDecorate; class SPIRVGroupDecorateGeneric; class SPIRVInstTemplateBase; class SPIRVAsmTargetINTEL; class SPIRVAsmINTEL; class SPIRVAsmCallINTEL; typedef SPIRVBasicBlock SPIRVLabel; struct SPIRVTypeImageDescriptor; template class SPIRVConstantBase; typedef SPIRVConstantBase SPIRVConstant; typedef std::unordered_map SPIRVSpecConstantMap; class SPIRVModule { public: typedef std::set SPIRVCapSet; static SPIRVModule* createSPIRVModule(); SPIRVModule(); virtual ~SPIRVModule(); // Object query functions virtual bool exist(SPIRVId) const = 0; virtual bool exist(SPIRVId, SPIRVEntry **)const = 0; template T* get(SPIRVId Id) const { return static_cast(getEntry(Id)); } virtual SPIRVEntry *getEntry(SPIRVId) const = 0; virtual void addUnknownStructField( SPIRVTypeStruct*, unsigned idx, SPIRVId id) = 0; virtual void resolveUnknownStructFields() = 0; virtual bool hasDebugInfo() const = 0; // Error handling functions virtual SPIRVErrorLog &getErrorLog() = 0; virtual SPIRVErrorCode getError(std::string&) = 0; // Module query functions virtual SPIRVAddressingModelKind getAddressingModel() = 0; virtual const SPIRVCapSet &getCapability() const = 0; virtual SPIRVExtInstSetKind getBuiltinSet(SPIRVId) const = 0; virtual bool isSpecConstantSpecialized(SPIRVWord) const = 0; virtual uint64_t getSpecConstant(SPIRVWord) = 0; virtual void setSpecConstantMap(SPIRVSpecConstantMap *) = 0; virtual SPIRVFunction *getEntryPoint(SPIRVExecutionModelKind, unsigned) const = 0; virtual std::set &getExtension() = 0; virtual SPIRVFunction *getFunction(unsigned) const = 0; virtual SPIRVAsmINTEL *getAsm(unsigned) const = 0; virtual SPIRVVariable *getVariable(unsigned) const = 0; virtual SPIRVMemoryModelKind getMemoryModel() = 0; virtual unsigned getNumFunctions() const = 0; virtual unsigned getNumEntryPoints(SPIRVExecutionModelKind) const = 0; virtual unsigned getNumVariables() const = 0; virtual SpvSourceLanguage getSourceLanguage(SPIRVWord *) const = 0; virtual std::set &getSourceExtension() = 0; virtual SPIRVValue *getValue(SPIRVId TheId)const = 0; virtual std::vector getValues(const std::vector&)const = 0; virtual std::vector getIds(const std::vector&)const = 0; virtual std::vector getIds(const std::vector&)const = 0; virtual SPIRVType *getValueType(SPIRVId TheId)const = 0; virtual std::vector getValueTypes(const std::vector&) const = 0; virtual SPIRVConstant* getLiteralAsConstant(unsigned Literal) = 0; virtual bool isEntryPoint(SPIRVExecutionModelKind, SPIRVId) const = 0; virtual const std::vector& getStringVec() const = 0; // Module changing functions virtual bool importBuiltinSet(const std::string &, SPIRVId *) = 0; virtual bool importBuiltinSetWithId(const std::string &, SPIRVId) = 0; virtual void setAddressingModel(SPIRVAddressingModelKind) = 0; virtual void setAlignment(SPIRVValue *, SPIRVWord) = 0; virtual void setMemoryModel(SPIRVMemoryModelKind) = 0; virtual void setName(SPIRVEntry *, const std::string&) = 0; virtual void setSourceLanguage(SpvSourceLanguage, SPIRVWord) = 0; virtual void optimizeDecorates() = 0; virtual void setModuleProcessed(const std::string& MP) = 0; // Object creation functions template T *add(T *Entry) { addEntry(Entry); return Entry; } virtual SPIRVEntry *addEntry(SPIRVEntry *) = 0; virtual SPIRVString *getString(const std::string &Str) = 0; virtual SPIRVMemberName *addMemberName(SPIRVTypeStruct *ST, SPIRVWord MemberNumber, const std::string &Name) = 0; virtual SPIRVLine *addLine(SPIRVString *FileName, SPIRVWord Line, SPIRVWord Column) = 0; virtual const SPIRVDecorateGeneric *addDecorate(const SPIRVDecorateGeneric*) = 0; virtual SPIRVDecorationGroup *addDecorationGroup() = 0; virtual SPIRVDecorationGroup *addDecorationGroup(SPIRVDecorationGroup *Group) = 0; virtual SPIRVGroupDecorate *addGroupDecorate(SPIRVDecorationGroup *Group, const std::vector &Targets) = 0; virtual SPIRVGroupMemberDecorate *addGroupMemberDecorate( SPIRVDecorationGroup *Group, const std::vector &Targets) = 0; virtual SPIRVGroupDecorateGeneric *addGroupDecorateGeneric( SPIRVGroupDecorateGeneric *GDec) = 0; virtual void addEntryPoint(SPIRVExecutionModelKind, SPIRVId) = 0; virtual SPIRVForward *addForward(SPIRVType *Ty) = 0; virtual SPIRVForward *addForward(SPIRVId, SPIRVType *Ty) = 0; virtual SPIRVFunction *addFunction(SPIRVFunction *) = 0; virtual SPIRVFunction *addFunction(SPIRVTypeFunction *, SPIRVId Id = SPIRVID_INVALID) = 0; virtual SPIRVEntry *replaceForward(SPIRVForward *, SPIRVEntry *) = 0; // Type creation functions virtual SPIRVTypeInt *addIntegerType(unsigned) = 0; // Constants creation functions virtual SPIRVValue *addConstant(SPIRVValue *) = 0; virtual SPIRVValue *addConstant(SPIRVType *, uint64_t) = 0; virtual SPIRVInstruction *addLoopMergeInst( SPIRVId MergeBlock, SPIRVId ContinueTarget, SPIRVWord LoopControl, std::vector LoopControlParameters, SPIRVBasicBlock *BB) = 0; virtual SPIRVEntry *addAsmTargetINTEL(const std::string &) = 0; virtual SPIRVValue *addAsmINTEL(SPIRVTypeFunction *, SPIRVAsmTargetINTEL *, const std::string &, const std::string &) = 0; virtual SPIRVInstruction *addAsmCallINTELInst(SPIRVAsmINTEL *, const std::vector &, SPIRVBasicBlock *) = 0; virtual void addCapability(SPIRVCapabilityKind) = 0; virtual SPIRVExtInst* getCompilationUnit() const = 0; virtual std::vector getGlobalVars() = 0; virtual std::vector parseSpecConstants() = 0; // I/O functions friend std::istream & operator>>(std::istream &I, SPIRVModule& M); }; class SPIRVDbgInfo { public: SPIRVDbgInfo(SPIRVModule *TM); std::string getEntryPointFileStr(SPIRVExecutionModelKind, unsigned); std::string getFunctionFileStr(SPIRVFunction *); unsigned getFunctionLineNo(SPIRVFunction *); private: std::unordered_map FuncMap; const std::string ModuleFileStr; SPIRVModule *M; }; } #endif /* SPIRVMODULE_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVOpCode.h000066400000000000000000000174651363533017100262470ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVOpCode.h - Class to represent SPIR-V Operation Codes -*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines Operation Code class for SPIR-V. /// //===----------------------------------------------------------------------===// #ifndef SPIRVOPCODE_HPP_ #define SPIRVOPCODE_HPP_ #include "SPIRVUtil.h" #include "spirv.hpp" #include #include "Probe.h" namespace spv{ template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x, ...) add(Op##x, #x); #include "SPIRVOpCodeEnum.h" #undef _SPIRV_OP } SPIRV_DEF_NAMEMAP(Op, OpCodeNameMap) inline bool isAtomicOpCode(Op OpCode) { IGC_ASSERT(OpAtomicLoad < OpAtomicXor); return ((unsigned)OpCode >= OpAtomicLoad && (unsigned)OpCode <= OpAtomicXor) || OpCode == OpAtomicFlagTestAndSet || OpCode == OpAtomicFlagClear; } inline bool isBinaryOpCode(Op OpCode) { return ((unsigned)OpCode >= OpIAdd && (unsigned)OpCode <= OpFMod) || OpCode == OpDot; } inline bool isShiftOpCode(Op OpCode) { return (unsigned)OpCode >= OpShiftRightLogical && (unsigned)OpCode <= OpShiftLeftLogical; } inline bool isLogicalOpCode(Op OpCode) { return (unsigned)OpCode >= OpLogicalEqual && (unsigned)OpCode <= OpLogicalNot; } inline bool isBitwiseOpCode(Op OpCode) { return (unsigned)OpCode >= OpBitwiseOr && (unsigned)OpCode <= OpBitwiseAnd; } inline bool isBinaryShiftLogicalBitwiseOpCode(Op OpCode) { return (((unsigned)OpCode >= OpShiftRightLogical && (unsigned)OpCode <= OpBitwiseAnd) || isBinaryOpCode(OpCode)); } inline bool isCmpOpCode(Op OpCode) { return ((unsigned)OpCode >= OpIEqual && (unsigned)OpCode <= OpFUnordGreaterThanEqual) || (OpCode >= OpLessOrGreater && OpCode <= OpLogicalNotEqual); } inline bool isCvtOpCode(Op OpCode) { return ((unsigned)OpCode >= OpConvertFToU && (unsigned)OpCode <= OpBitcast) || OpCode == OpSatConvertSToU || OpCode == OpSatConvertUToS; } inline bool isCvtToUnsignedOpCode(Op OpCode) { return OpCode == OpConvertFToU || OpCode == OpUConvert || OpCode == OpSatConvertSToU; } inline bool isCvtFromUnsignedOpCode(Op OpCode) { return OpCode == OpConvertUToF || OpCode == OpUConvert || OpCode == OpSatConvertUToS; } inline bool isOpaqueGenericTypeOpCode(Op OpCode) { return (unsigned)OpCode >= OpTypeEvent && (unsigned)OpCode <= OpTypePipe; } inline bool isGenericNegateOpCode(Op OpCode) { return (unsigned)OpCode == OpSNegate || (unsigned)OpCode == OpFNegate || (unsigned)OpCode == OpNot; } inline bool isAccessChainOpCode(Op OpCode) { return OpCode == OpAccessChain || OpCode == OpInBoundsAccessChain; } inline bool hasExecScope(Op OpCode) { unsigned OC = OpCode; return (OpGroupWaitEvents <= OC && OC <= OpGroupSMax) || (OpGroupReserveReadPipePackets <= OC && OC <= OpGroupCommitWritePipe); } inline bool hasGroupOperation(Op OpCode) { unsigned OC = OpCode; return (OpGroupIAdd <= OC && OC <= OpGroupSMax) || (OpGroupNonUniformIAdd <= OC && OC <= OpGroupNonUniformLogicalXor); } inline bool isSubgroupAvcINTELTypeOpCode(Op OpCode) { unsigned OC = OpCode; return OpTypeAvcImePayloadINTEL <= OC && OC <= OpTypeAvcSicResultINTEL; } inline unsigned getSubgroupAvcINTELTypeVectorWidth(Op Opcode) { IGC_ASSERT(isSubgroupAvcINTELTypeOpCode(Opcode)); switch (Opcode) { case OpTypeAvcImeResultSingleReferenceStreamoutINTEL: case OpTypeAvcImeResultDualReferenceStreamoutINTEL: return 8; case OpTypeAvcImePayloadINTEL: case OpTypeAvcRefPayloadINTEL: case OpTypeAvcSicPayloadINTEL: case OpTypeAvcMcePayloadINTEL: case OpTypeAvcMceResultINTEL: case OpTypeAvcImeResultINTEL: case OpTypeAvcRefResultINTEL: case OpTypeAvcSicResultINTEL: return 4; case OpTypeAvcImeDualReferenceStreaminINTEL: return 2; case OpTypeAvcImeSingleReferenceStreaminINTEL: // Scalar. return 1; default: IGC_ASSERT(0 && "Unknown VME Opcode!"); return 0; } } inline bool isTypeOpCode(Op OpCode) { unsigned OC = OpCode; return (OpTypeVoid <= OC && OC <= OpTypePipe) || isSubgroupAvcINTELTypeOpCode(OpCode) || OC == OpTypeVmeImageINTEL; } inline bool isConstantOpCode(Op OpCode) { unsigned OC = OpCode; return (OpConstantTrue <= OC && OC <= OpSpecConstantOp) || OC == OpUndef; } inline bool isModuleScopeAllowedOpCode(Op OpCode) { return OpCode == OpVariable || isConstantOpCode(OpCode); } inline bool isImageOpCode(Op OpCode) { return (OpCode >= OpImageSampleImplicitLod) && (OpCode <= OpImageWrite); } inline bool isIntelSubgroupOpCode(Op OpCode) { unsigned OC = OpCode; return OpSubgroupShuffleINTEL <= OC && OC <= OpSubgroupImageMediaBlockWriteINTEL; } inline bool isIntelVMEOpCode(Op OpCode) { unsigned OC = OpCode; return OpVmeImageINTEL <= OC && OC <= OpSubgroupAvcSicGetInterRawSadsINTEL; } } #endif /* SPIRVOPCODE_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVOpCodeEnum.h000066400000000000000000000463101363533017100270630ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ _SPIRV_OP(Nop, 0) _SPIRV_OP(Undef, 1) _SPIRV_OP(SizeOf, 321) _SPIRV_OP(SourceContinued, 2) _SPIRV_OP(Source, 3) _SPIRV_OP(SourceExtension, 4) _SPIRV_OP(Name, 5) _SPIRV_OP(MemberName, 6) _SPIRV_OP(String, 7) _SPIRV_OP(Line, 8) _SPIRV_OP(Extension, 10) _SPIRV_OP(ExtInstImport, 11) _SPIRV_OP(ExtInst, 12) _SPIRV_OP(MemoryModel, 14) _SPIRV_OP(EntryPoint, 15) _SPIRV_OP(ExecutionMode, 16) _SPIRV_OP(Capability, 17) _SPIRV_OP(TypeVoid, 19) _SPIRV_OP(TypeBool, 20) _SPIRV_OP(TypeInt, 21) _SPIRV_OP(TypeFloat, 22) _SPIRV_OP(TypeVector, 23) _SPIRV_OP(TypeMatrix, 24) _SPIRV_OP(TypeImage, 25) _SPIRV_OP(TypeSampler, 26) _SPIRV_OP(TypeSampledImage, 27) _SPIRV_OP(TypeArray, 28) _SPIRV_OP(TypeRuntimeArray, 29) _SPIRV_OP(TypeStruct, 30) _SPIRV_OP(TypeOpaque, 31) _SPIRV_OP(TypePointer, 32) _SPIRV_OP(TypeFunction, 33) _SPIRV_OP(TypeEvent, 34) _SPIRV_OP(TypeDeviceEvent, 35) _SPIRV_OP(TypeReserveId, 36) _SPIRV_OP(TypeQueue, 37) _SPIRV_OP(TypePipe, 38) _SPIRV_OP(TypePipeStorage, 322) _SPIRV_OP(TypeForwardPointer, 39) _SPIRV_OP(ConstantTrue, 41) _SPIRV_OP(ConstantFalse, 42) _SPIRV_OP(Constant, 43) _SPIRV_OP(ConstantComposite, 44) _SPIRV_OP(ConstantSampler, 45) _SPIRV_OP(ConstantNull, 46) _SPIRV_OP(SpecConstantTrue, 48) _SPIRV_OP(SpecConstantFalse, 49) _SPIRV_OP(SpecConstant, 50) _SPIRV_OP(SpecConstantComposite, 51) _SPIRV_OP(SpecConstantOp, 52) _SPIRV_OP(Function, 54) _SPIRV_OP(FunctionParameter, 55) _SPIRV_OP(FunctionEnd, 56) _SPIRV_OP(FunctionCall, 57) _SPIRV_OP(Variable, 59) _SPIRV_OP(ImageTexelPointer, 60) _SPIRV_OP(Load, 61) _SPIRV_OP(Store, 62) _SPIRV_OP(CopyMemory, 63) _SPIRV_OP(CopyMemorySized, 64) _SPIRV_OP(AccessChain, 65) _SPIRV_OP(InBoundsAccessChain, 66) _SPIRV_OP(PtrAccessChain, 67) _SPIRV_OP(ArrayLength, 68) _SPIRV_OP(GenericPtrMemSemantics, 69) _SPIRV_OP(InBoundsPtrAccessChain, 70) _SPIRV_OP(Decorate, 71) _SPIRV_OP(MemberDecorate, 72) _SPIRV_OP(DecorationGroup, 73) _SPIRV_OP(GroupDecorate, 74) _SPIRV_OP(GroupMemberDecorate, 75) _SPIRV_OP(VectorExtractDynamic, 77) _SPIRV_OP(VectorInsertDynamic, 78) _SPIRV_OP(VectorShuffle, 79) _SPIRV_OP(CompositeConstruct, 80) _SPIRV_OP(CompositeExtract, 81) _SPIRV_OP(CompositeInsert, 82) _SPIRV_OP(CopyObject, 83) _SPIRV_OP(Transpose, 84) _SPIRV_OP(SampledImage, 86) _SPIRV_OP(ImageSampleImplicitLod, 87) _SPIRV_OP(ImageSampleExplicitLod, 88) _SPIRV_OP(ImageSampleDrefImplicitLod, 89) _SPIRV_OP(ImageSampleDrefExplicitLod, 90) _SPIRV_OP(ImageSampleProjImplicitLod, 91) _SPIRV_OP(ImageSampleProjExplicitLod, 92) _SPIRV_OP(ImageSampleProjDrefImplicitLod, 93) _SPIRV_OP(ImageSampleProjDrefExplicitLod, 94) _SPIRV_OP(ImageFetch, 95) _SPIRV_OP(ImageGather, 96) _SPIRV_OP(ImageDrefGather, 97) _SPIRV_OP(ImageRead, 98) _SPIRV_OP(ImageWrite, 99) _SPIRV_OP(ImageQueryFormat, 101) _SPIRV_OP(ImageQueryOrder, 102) _SPIRV_OP(ImageQuerySizeLod, 103) _SPIRV_OP(ImageQuerySize, 104) _SPIRV_OP(ImageQueryLod, 105) _SPIRV_OP(ImageQueryLevels, 106) _SPIRV_OP(ImageQuerySamples, 107) _SPIRV_OP(ConvertFToU, 109) _SPIRV_OP(ConvertFToS, 110) _SPIRV_OP(ConvertSToF, 111) _SPIRV_OP(ConvertUToF, 112) _SPIRV_OP(UConvert, 113) _SPIRV_OP(SConvert, 114) _SPIRV_OP(FConvert, 115) _SPIRV_OP(QuantizeToF16, 116) _SPIRV_OP(ConvertPtrToU, 117) _SPIRV_OP(SatConvertSToU, 118) _SPIRV_OP(SatConvertUToS, 119) _SPIRV_OP(ConvertUToPtr, 120) _SPIRV_OP(PtrCastToGeneric, 121) _SPIRV_OP(GenericCastToPtr, 122) _SPIRV_OP(GenericCastToPtrExplicit, 123) _SPIRV_OP(Bitcast, 124) _SPIRV_OP(SNegate, 126) _SPIRV_OP(FNegate, 127) _SPIRV_OP(IAdd, 128) _SPIRV_OP(FAdd, 129) _SPIRV_OP(ISub, 130) _SPIRV_OP(FSub, 131) _SPIRV_OP(IMul, 132) _SPIRV_OP(FMul, 133) _SPIRV_OP(UDiv, 134) _SPIRV_OP(SDiv, 135) _SPIRV_OP(FDiv, 136) _SPIRV_OP(UMod, 137) _SPIRV_OP(SRem, 138) _SPIRV_OP(SMod, 139) _SPIRV_OP(FRem, 140) _SPIRV_OP(FMod, 141) _SPIRV_OP(VectorTimesScalar, 142) _SPIRV_OP(MatrixTimesScalar, 143) _SPIRV_OP(VectorTimesMatrix, 144) _SPIRV_OP(MatrixTimesVector, 145) _SPIRV_OP(MatrixTimesMatrix, 146) _SPIRV_OP(OuterProduct, 147) _SPIRV_OP(Dot, 148) _SPIRV_OP(IAddCarry, 149) _SPIRV_OP(ISubBorrow, 150) _SPIRV_OP(UMulExtended, 151) _SPIRV_OP(SMulExtended, 152) _SPIRV_OP(Any, 154) _SPIRV_OP(All, 155) _SPIRV_OP(IsNan, 156) _SPIRV_OP(IsInf, 157) _SPIRV_OP(IsFinite, 158) _SPIRV_OP(IsNormal, 159) _SPIRV_OP(SignBitSet, 160) _SPIRV_OP(LessOrGreater, 161) _SPIRV_OP(Ordered, 162) _SPIRV_OP(Unordered, 163) _SPIRV_OP(LogicalEqual, 164) _SPIRV_OP(LogicalNotEqual, 165) _SPIRV_OP(LogicalOr, 166) _SPIRV_OP(LogicalAnd, 167) _SPIRV_OP(LogicalNot, 168) _SPIRV_OP(Select, 169) _SPIRV_OP(IEqual, 170) _SPIRV_OP(INotEqual, 171) _SPIRV_OP(UGreaterThan, 172) _SPIRV_OP(SGreaterThan, 173) _SPIRV_OP(UGreaterThanEqual, 174) _SPIRV_OP(SGreaterThanEqual, 175) _SPIRV_OP(ULessThan, 176) _SPIRV_OP(SLessThan, 177) _SPIRV_OP(ULessThanEqual, 178) _SPIRV_OP(SLessThanEqual, 179) _SPIRV_OP(FOrdEqual, 180) _SPIRV_OP(FUnordEqual, 181) _SPIRV_OP(FOrdNotEqual, 182) _SPIRV_OP(FUnordNotEqual, 183) _SPIRV_OP(FOrdLessThan, 184) _SPIRV_OP(FUnordLessThan, 185) _SPIRV_OP(FOrdGreaterThan, 186) _SPIRV_OP(FUnordGreaterThan, 187) _SPIRV_OP(FOrdLessThanEqual, 188) _SPIRV_OP(FUnordLessThanEqual, 189) _SPIRV_OP(FOrdGreaterThanEqual, 190) _SPIRV_OP(FUnordGreaterThanEqual, 191) _SPIRV_OP(ShiftRightLogical, 194) _SPIRV_OP(ShiftRightArithmetic, 195) _SPIRV_OP(ShiftLeftLogical, 196) _SPIRV_OP(BitwiseOr, 197) _SPIRV_OP(BitwiseXor, 198) _SPIRV_OP(BitwiseAnd, 199) _SPIRV_OP(Not, 200) _SPIRV_OP(BitFieldInsert, 201) _SPIRV_OP(BitFieldSExtract, 202) _SPIRV_OP(BitFieldUExtract, 203) _SPIRV_OP(BitReverse, 204) _SPIRV_OP(BitCount, 205) _SPIRV_OP(DPdx, 207) _SPIRV_OP(DPdy, 208) _SPIRV_OP(Fwidth, 209) _SPIRV_OP(DPdxFine, 210) _SPIRV_OP(DPdyFine, 211) _SPIRV_OP(FwidthFine, 212) _SPIRV_OP(DPdxCoarse, 213) _SPIRV_OP(DPdyCoarse, 214) _SPIRV_OP(FwidthCoarse, 215) _SPIRV_OP(EmitVertex, 218) _SPIRV_OP(EndPrimitive, 219) _SPIRV_OP(EmitStreamVertex, 220) _SPIRV_OP(EndStreamPrimitive, 221) _SPIRV_OP(ControlBarrier, 224) _SPIRV_OP(MemoryBarrier, 225) _SPIRV_OP(AtomicLoad, 227) _SPIRV_OP(AtomicStore, 228) _SPIRV_OP(AtomicExchange, 229) _SPIRV_OP(AtomicCompareExchange, 230) _SPIRV_OP(AtomicCompareExchangeWeak, 231) _SPIRV_OP(AtomicIIncrement, 232) _SPIRV_OP(AtomicIDecrement, 233) _SPIRV_OP(AtomicIAdd, 234) _SPIRV_OP(AtomicISub, 235) _SPIRV_OP(AtomicSMin, 236) _SPIRV_OP(AtomicUMin, 237) _SPIRV_OP(AtomicSMax, 238) _SPIRV_OP(AtomicUMax, 239) _SPIRV_OP(AtomicAnd, 240) _SPIRV_OP(AtomicOr, 241) _SPIRV_OP(AtomicXor, 242) _SPIRV_OP(Phi, 245) _SPIRV_OP(LoopMerge, 246) _SPIRV_OP(SelectionMerge, 247) _SPIRV_OP(Label, 248) _SPIRV_OP(Branch, 249) _SPIRV_OP(BranchConditional, 250) _SPIRV_OP(Switch, 251) _SPIRV_OP(Kill, 252) _SPIRV_OP(Return, 253) _SPIRV_OP(ReturnValue, 254) _SPIRV_OP(Unreachable, 255) _SPIRV_OP(LifetimeStart, 256) _SPIRV_OP(LifetimeStop, 257) _SPIRV_OP(GroupAsyncCopy, 259) _SPIRV_OP(GroupWaitEvents, 260) _SPIRV_OP(GroupAll, 261) _SPIRV_OP(GroupAny, 262) _SPIRV_OP(GroupBroadcast, 263) _SPIRV_OP(GroupIAdd, 264) _SPIRV_OP(GroupFAdd, 265) _SPIRV_OP(GroupFMin, 266) _SPIRV_OP(GroupUMin, 267) _SPIRV_OP(GroupSMin, 268) _SPIRV_OP(GroupFMax, 269) _SPIRV_OP(GroupUMax, 270) _SPIRV_OP(GroupSMax, 271) _SPIRV_OP(ReadPipe, 274) _SPIRV_OP(WritePipe, 275) _SPIRV_OP(ReservedReadPipe, 276) _SPIRV_OP(ReservedWritePipe, 277) _SPIRV_OP(ReserveReadPipePackets, 278) _SPIRV_OP(ReserveWritePipePackets, 279) _SPIRV_OP(CommitReadPipe, 280) _SPIRV_OP(CommitWritePipe, 281) _SPIRV_OP(IsValidReserveId, 282) _SPIRV_OP(GetNumPipePackets, 283) _SPIRV_OP(GetMaxPipePackets, 284) _SPIRV_OP(GroupReserveReadPipePackets, 285) _SPIRV_OP(GroupReserveWritePipePackets, 286) _SPIRV_OP(GroupCommitReadPipe, 287) _SPIRV_OP(GroupCommitWritePipe, 288) _SPIRV_OP(ConstantPipeStorage, 323) _SPIRV_OP(CreatePipeFromPipeStorage, 324) _SPIRV_OP(EnqueueMarker, 291) _SPIRV_OP(EnqueueKernel, 292) _SPIRV_OP(GetKernelNDrangeSubGroupCount, 293) _SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, 294) _SPIRV_OP(GetKernelWorkGroupSize, 295) _SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, 296) _SPIRV_OP(RetainEvent, 297) _SPIRV_OP(ReleaseEvent, 298) _SPIRV_OP(CreateUserEvent, 299) _SPIRV_OP(IsValidEvent, 300) _SPIRV_OP(SetUserEventStatus, 301) _SPIRV_OP(CaptureEventProfilingInfo, 302) _SPIRV_OP(GetDefaultQueue, 303) _SPIRV_OP(BuildNDRange, 304) _SPIRV_OP(GetKernelLocalSizeForSubgroupCount, 325) _SPIRV_OP(GetKernelMaxNumSubgroups, 326) _SPIRV_OP(ImageSparseSampleImplicitLod, 305) _SPIRV_OP(ImageSparseSampleExplicitLod, 306) _SPIRV_OP(ImageSparseSampleDrefImplicitLod, 307) _SPIRV_OP(ImageSparseSampleDrefExplicitLod, 308) _SPIRV_OP(ImageSparseSampleProjImplicitLod, 309) _SPIRV_OP(ImageSparseSampleProjExplicitLod, 310) _SPIRV_OP(ImageSparseSampleProjDrefImplicitLod, 311) _SPIRV_OP(ImageSparseSampleProjDrefExplicitLod, 312) _SPIRV_OP(ImageSparseFetch, 313) _SPIRV_OP(ImageSparseGather, 314) _SPIRV_OP(ImageSparseDrefGather, 315) _SPIRV_OP(ImageSparseTexelsResident, 316) _SPIRV_OP(NoLine, 317) _SPIRV_OP(AtomicFlagTestAndSet, 318) _SPIRV_OP(AtomicFlagClear, 319) _SPIRV_OP(TypeNamedBarrier, 327) _SPIRV_OP(NamedBarrierInitialize, 328) _SPIRV_OP(MemoryNamedBarrier, 329) _SPIRV_OP(ModuleProcessed, 330) // SPIR-V 1.3 non uniform subgroup builtins _SPIRV_OP(GroupNonUniformElect, 333) _SPIRV_OP(GroupNonUniformAll, 334) _SPIRV_OP(GroupNonUniformAny, 335) _SPIRV_OP(GroupNonUniformAllEqual, 336) _SPIRV_OP(GroupNonUniformBroadcast, 337) _SPIRV_OP(GroupNonUniformBroadcastFirst, 338) _SPIRV_OP(GroupNonUniformBallot, 339) _SPIRV_OP(GroupNonUniformInverseBallot, 340) _SPIRV_OP(GroupNonUniformBallotBitExtract, 341) _SPIRV_OP(GroupNonUniformBallotBitCount, 342) _SPIRV_OP(GroupNonUniformBallotFindLSB, 343) _SPIRV_OP(GroupNonUniformBallotFindMSB, 344) _SPIRV_OP(GroupNonUniformShuffle, 345) _SPIRV_OP(GroupNonUniformShuffleXor, 346) _SPIRV_OP(GroupNonUniformShuffleUp, 347) _SPIRV_OP(GroupNonUniformShuffleDown, 348) _SPIRV_OP(GroupNonUniformIAdd, 349) _SPIRV_OP(GroupNonUniformFAdd, 350) _SPIRV_OP(GroupNonUniformIMul, 351) _SPIRV_OP(GroupNonUniformFMul, 352) _SPIRV_OP(GroupNonUniformSMin, 353) _SPIRV_OP(GroupNonUniformUMin, 354) _SPIRV_OP(GroupNonUniformFMin, 355) _SPIRV_OP(GroupNonUniformSMax, 356) _SPIRV_OP(GroupNonUniformUMax, 357) _SPIRV_OP(GroupNonUniformFMax, 358) _SPIRV_OP(GroupNonUniformBitwiseAnd, 359) _SPIRV_OP(GroupNonUniformBitwiseOr, 360) _SPIRV_OP(GroupNonUniformBitwiseXor, 361) _SPIRV_OP(GroupNonUniformLogicalAnd, 362) _SPIRV_OP(GroupNonUniformLogicalOr, 363) _SPIRV_OP(GroupNonUniformLogicalXor, 364) // Ballot extension _SPIRV_OP(SubgroupBallotKHR, 4421) _SPIRV_OP(SubgroupFirstInvocationKHR, 4422) // Shader clock extension _SPIRV_OP(ReadClockKHR, 5055) _SPIRV_OP(Forward, 1024) // Internal only _SPIRV_OP(SubgroupShuffleINTEL, 5571) _SPIRV_OP(SubgroupShuffleDownINTEL, 5572) _SPIRV_OP(SubgroupShuffleUpINTEL, 5573) _SPIRV_OP(SubgroupShuffleXorINTEL, 5574) _SPIRV_OP(SubgroupBlockReadINTEL, 5575) _SPIRV_OP(SubgroupBlockWriteINTEL, 5576) _SPIRV_OP(SubgroupImageBlockReadINTEL, 5577) _SPIRV_OP(SubgroupImageBlockWriteINTEL, 5578) // media_block_io extension. _SPIRV_OP(SubgroupImageMediaBlockReadINTEL, 5580) _SPIRV_OP(SubgroupImageMediaBlockWriteINTEL, 5581) _SPIRV_OP(AsmTargetINTEL, 5609) _SPIRV_OP(AsmINTEL, 5610) _SPIRV_OP(AsmCallINTEL, 5611) // Function pointers _SPIRV_OP(FunctionPointerINTEL, 5600) _SPIRV_OP(FunctionPointerCallINTEL, 5601) // device_side_avc_motion_estimation extension _SPIRV_OP(VmeImageINTEL, 5699) _SPIRV_OP(TypeVmeImageINTEL, 5700) _SPIRV_OP(TypeAvcImePayloadINTEL, 5701) _SPIRV_OP(TypeAvcRefPayloadINTEL, 5702) _SPIRV_OP(TypeAvcSicPayloadINTEL, 5703) _SPIRV_OP(TypeAvcMcePayloadINTEL, 5704) _SPIRV_OP(TypeAvcMceResultINTEL, 5705) _SPIRV_OP(TypeAvcImeResultINTEL, 5706) _SPIRV_OP(TypeAvcImeResultSingleReferenceStreamoutINTEL, 5707) _SPIRV_OP(TypeAvcImeResultDualReferenceStreamoutINTEL, 5708) _SPIRV_OP(TypeAvcImeSingleReferenceStreaminINTEL, 5709) _SPIRV_OP(TypeAvcImeDualReferenceStreaminINTEL, 5710) _SPIRV_OP(TypeAvcRefResultINTEL, 5711) _SPIRV_OP(TypeAvcSicResultINTEL, 5712) _SPIRV_OP(SubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL, 5713) _SPIRV_OP(SubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL, 5714) _SPIRV_OP(SubgroupAvcMceGetDefaultInterShapePenaltyINTEL, 5715) _SPIRV_OP(SubgroupAvcMceSetInterShapePenaltyINTEL, 5716) _SPIRV_OP(SubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL, 5717) _SPIRV_OP(SubgroupAvcMceSetInterDirectionPenaltyINTEL, 5718) _SPIRV_OP(SubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL, 5719) _SPIRV_OP(SubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL, 5720) _SPIRV_OP(SubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL, 5721) _SPIRV_OP(SubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL, 5722) _SPIRV_OP(SubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL, 5723) _SPIRV_OP(SubgroupAvcMceSetMotionVectorCostFunctionINTEL, 5724) _SPIRV_OP(SubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL, 5725) _SPIRV_OP(SubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL, 5726) _SPIRV_OP(SubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL, 5727) _SPIRV_OP(SubgroupAvcMceSetAcOnlyHaarINTEL, 5728) _SPIRV_OP(SubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL, 5729) _SPIRV_OP(SubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL, 5730) _SPIRV_OP(SubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL, 5731) _SPIRV_OP(SubgroupAvcMceConvertToImePayloadINTEL, 5732) _SPIRV_OP(SubgroupAvcMceConvertToImeResultINTEL, 5733) _SPIRV_OP(SubgroupAvcMceConvertToRefPayloadINTEL, 5734) _SPIRV_OP(SubgroupAvcMceConvertToRefResultINTEL, 5735) _SPIRV_OP(SubgroupAvcMceConvertToSicPayloadINTEL, 5736) _SPIRV_OP(SubgroupAvcMceConvertToSicResultINTEL, 5737) _SPIRV_OP(SubgroupAvcMceGetMotionVectorsINTEL, 5738) _SPIRV_OP(SubgroupAvcMceGetInterDistortionsINTEL, 5739) _SPIRV_OP(SubgroupAvcMceGetBestInterDistortionsINTEL, 5740) _SPIRV_OP(SubgroupAvcMceGetInterMajorShapeINTEL, 5741) _SPIRV_OP(SubgroupAvcMceGetInterMinorShapeINTEL, 5742) _SPIRV_OP(SubgroupAvcMceGetInterDirectionsINTEL, 5743) _SPIRV_OP(SubgroupAvcMceGetInterMotionVectorCountINTEL, 5744) _SPIRV_OP(SubgroupAvcMceGetInterReferenceIdsINTEL, 5745) _SPIRV_OP(SubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL, 5746) _SPIRV_OP(SubgroupAvcImeInitializeINTEL, 5747) _SPIRV_OP(SubgroupAvcImeSetSingleReferenceINTEL, 5748) _SPIRV_OP(SubgroupAvcImeSetDualReferenceINTEL, 5749) _SPIRV_OP(SubgroupAvcImeRefWindowSizeINTEL, 5750) _SPIRV_OP(SubgroupAvcImeAdjustRefOffsetINTEL, 5751) _SPIRV_OP(SubgroupAvcImeConvertToMcePayloadINTEL, 5752) _SPIRV_OP(SubgroupAvcImeSetMaxMotionVectorCountINTEL, 5753) _SPIRV_OP(SubgroupAvcImeSetUnidirectionalMixDisableINTEL, 5754) _SPIRV_OP(SubgroupAvcImeSetEarlySearchTerminationThresholdINTEL, 5755) _SPIRV_OP(SubgroupAvcImeSetWeightedSadINTEL, 5756) _SPIRV_OP(SubgroupAvcImeEvaluateWithSingleReferenceINTEL, 5757) _SPIRV_OP(SubgroupAvcImeEvaluateWithDualReferenceINTEL, 5758) _SPIRV_OP(SubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL, 5759) _SPIRV_OP(SubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL, 5760) _SPIRV_OP(SubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL, 5761) _SPIRV_OP(SubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL, 5762) _SPIRV_OP(SubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL, 5763) _SPIRV_OP(SubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL, 5764) _SPIRV_OP(SubgroupAvcImeConvertToMceResultINTEL, 5765) _SPIRV_OP(SubgroupAvcImeGetSingleReferenceStreaminINTEL, 5766) _SPIRV_OP(SubgroupAvcImeGetDualReferenceStreaminINTEL, 5767) _SPIRV_OP(SubgroupAvcImeStripSingleReferenceStreamoutINTEL, 5768) _SPIRV_OP(SubgroupAvcImeStripDualReferenceStreamoutINTEL, 5769) _SPIRV_OP(SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL, 5770) _SPIRV_OP(SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL, 5771) _SPIRV_OP(SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL, 5772) _SPIRV_OP(SubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL, 5773) _SPIRV_OP(SubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL, 5774) _SPIRV_OP(SubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL, 5775) _SPIRV_OP(SubgroupAvcImeGetBorderReachedINTEL, 5776) _SPIRV_OP(SubgroupAvcImeGetTruncatedSearchIndicationINTEL, 5777) _SPIRV_OP(SubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL, 5778) _SPIRV_OP(SubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL, 5779) _SPIRV_OP(SubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL, 5780) _SPIRV_OP(SubgroupAvcFmeInitializeINTEL, 5781) _SPIRV_OP(SubgroupAvcBmeInitializeINTEL, 5782) _SPIRV_OP(SubgroupAvcRefConvertToMcePayloadINTEL, 5783) _SPIRV_OP(SubgroupAvcRefSetBidirectionalMixDisableINTEL, 5784) _SPIRV_OP(SubgroupAvcRefSetBilinearFilterEnableINTEL, 5785) _SPIRV_OP(SubgroupAvcRefEvaluateWithSingleReferenceINTEL, 5786) _SPIRV_OP(SubgroupAvcRefEvaluateWithDualReferenceINTEL, 5787) _SPIRV_OP(SubgroupAvcRefEvaluateWithMultiReferenceINTEL, 5788) _SPIRV_OP(SubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL, 5789) _SPIRV_OP(SubgroupAvcRefConvertToMceResultINTEL, 5790) _SPIRV_OP(SubgroupAvcSicInitializeINTEL, 5791) _SPIRV_OP(SubgroupAvcSicConfigureSkcINTEL, 5792) _SPIRV_OP(SubgroupAvcSicConfigureIpeLumaINTEL, 5793) _SPIRV_OP(SubgroupAvcSicConfigureIpeLumaChromaINTEL, 5794) _SPIRV_OP(SubgroupAvcSicGetMotionVectorMaskINTEL, 5795) _SPIRV_OP(SubgroupAvcSicConvertToMcePayloadINTEL, 5796) _SPIRV_OP(SubgroupAvcSicSetIntraLumaShapePenaltyINTEL, 5797) _SPIRV_OP(SubgroupAvcSicSetIntraLumaModeCostFunctionINTEL, 5798) _SPIRV_OP(SubgroupAvcSicSetIntraChromaModeCostFunctionINTEL, 5799) _SPIRV_OP(SubgroupAvcSicSetBilinearFilterEnableINTEL, 5800) _SPIRV_OP(SubgroupAvcSicSetSkcForwardTransformEnableINTEL, 5801) _SPIRV_OP(SubgroupAvcSicSetBlockBasedRawSkipSadINTEL, 5802) _SPIRV_OP(SubgroupAvcSicEvaluateIpeINTEL, 5803) _SPIRV_OP(SubgroupAvcSicEvaluateWithSingleReferenceINTEL, 5804) _SPIRV_OP(SubgroupAvcSicEvaluateWithDualReferenceINTEL, 5805) _SPIRV_OP(SubgroupAvcSicEvaluateWithMultiReferenceINTEL, 5806) _SPIRV_OP(SubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL, 5807) _SPIRV_OP(SubgroupAvcSicConvertToMceResultINTEL, 5808) _SPIRV_OP(SubgroupAvcSicGetIpeLumaShapeINTEL, 5809) _SPIRV_OP(SubgroupAvcSicGetBestIpeLumaDistortionINTEL, 5810) _SPIRV_OP(SubgroupAvcSicGetBestIpeChromaDistortionINTEL, 5811) _SPIRV_OP(SubgroupAvcSicGetPackedIpeLumaModesINTEL, 5812) _SPIRV_OP(SubgroupAvcSicGetIpeChromaModeINTEL, 5813) _SPIRV_OP(SubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL, 5814) _SPIRV_OP(SubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL, 5815) _SPIRV_OP(SubgroupAvcSicGetInterRawSadsINTEL, 5816) intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVStream.cpp000066400000000000000000000163711363533017100266570ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVStream.cpp - Class to represent a SPIR-V Stream ------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements SPIR-V stream class. /// //===----------------------------------------------------------------------===// #include "SPIRVDebug.h" #include "SPIRVStream.h" #include "SPIRVFunction.h" #include "SPIRVInstruction.h" #include "SPIRVDebugInfoExt.h" #include "Probe.h" namespace spv{ SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVFunction &F) :IS(InputStream), M(*F.getModule()), WordCount(0), OpCode(OpNop), Scope(&F){} SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVBasicBlock &BB) :IS(InputStream), M(*BB.getModule()), WordCount(0), OpCode(OpNop), Scope(&BB){} void SPIRVDecoder::setScope(SPIRVEntry *TheScope) { IGC_ASSERT(TheScope && (TheScope->getOpCode() == OpFunction || TheScope->getOpCode() == OpLabel)); Scope = TheScope; } template<> const SPIRVDecoder& DecodeBinary(const SPIRVDecoder& I, bool &V) { SPIRVWord W; I.IS.read(reinterpret_cast(&W), sizeof(W)); V = (W == 0) ? false : true; return I; } template<> const SPIRVDecoder& DecodeBinary(const SPIRVDecoder& I, SPIRVWord &V) { I.IS.read(reinterpret_cast(&V), sizeof(V)); return I; } template const SPIRVDecoder& DecodeBinary(const SPIRVDecoder& I, T &V) { SPIRVWord W; DecodeBinary(I,W); V = static_cast(W); return I; } //explicitly instantiate DecodeBinary for enum types #define INSTANTIATE_DECODER_BINARY(Type) \ template \ const SPIRVDecoder& DecodeBinary \ (const SPIRVDecoder& I, Type &V); INSTANTIATE_DECODER_BINARY(enum spv::StorageClass) INSTANTIATE_DECODER_BINARY(enum spv::Dim) INSTANTIATE_DECODER_BINARY(enum spv::AccessQualifier) INSTANTIATE_DECODER_BINARY(enum spv::Scope) INSTANTIATE_DECODER_BINARY(enum spv::ExecutionModel) INSTANTIATE_DECODER_BINARY(enum spv::ExecutionMode) INSTANTIATE_DECODER_BINARY(enum spv::AddressingModel) INSTANTIATE_DECODER_BINARY(enum spv::MemoryModel) INSTANTIATE_DECODER_BINARY(enum spv::SpvSourceLanguage) INSTANTIATE_DECODER_BINARY(enum spv::Capability) INSTANTIATE_DECODER_BINARY(enum spv::SPIRVVersionSupported) INSTANTIATE_DECODER_BINARY(enum spv::SPIRVGeneratorKind) INSTANTIATE_DECODER_BINARY(enum spv::SPIRVInstructionSchemaKind) #undef SPIRV_DEF_DEC template const SPIRVDecoder& decode(const SPIRVDecoder& I, T &V) { return DecodeBinary(I, V); } #define SPIRV_DEF_DEC(Type) \ const SPIRVDecoder& operator>>(const SPIRVDecoder& I, Type &V) { \ return decode(I, V); \ } SPIRV_DEF_DEC(Op) SPIRV_DEF_DEC(Decoration) SPIRV_DEF_DEC(OCLExtOpKind) SPIRV_DEF_DEC(OCLExtOpDbgKind) #undef SPIRV_DEF_DEC // Read a string with padded 0's at the end so that they form a stream of // words. const SPIRVDecoder& operator>>(const SPIRVDecoder&I, std::string& Str) { uint64_t Count = 0; char Ch; while ((!I.IS.eof() && I.IS.get(Ch)) && Ch != '\0') { Str += Ch; ++Count; } Count = (Count + 1) % 4; Count = Count ? 4 - Count : 0; for (;Count; --Count) { (!I.IS.eof() && I.IS.get(Ch)); IGC_ASSERT(Ch == '\0' && "Invalid string in SPIRV"); } return I; } bool SPIRVDecoder::getWordCountAndOpCode() { if (IS.eof()) { WordCount = 0; OpCode = OpNop; return false; } SPIRVWord WordCountAndOpCode; *this >> WordCountAndOpCode; WordCount = WordCountAndOpCode >> 16; OpCode = static_cast(WordCountAndOpCode & 0xFFFF); IGC_ASSERT(!IS.bad() && "SPIRV stream is bad"); if (IS.fail()) { WordCount = 0; OpCode = OpNop; return false; } return true; } SPIRVEntry * SPIRVDecoder::getEntry() { if (WordCount == 0 || OpCode == OpNop) return NULL; SPIRVEntry *Entry = SPIRVEntry::create(OpCode); Entry->setModule(&M); Entry->setWordCount(WordCount); IS >> *Entry; if ((isModuleScopeAllowedOpCode(OpCode) && !Scope) || // No need to attach scope to debug info extension operations (Entry->hasNoScope())) {} else Entry->setScope(Scope); IGC_ASSERT(!IS.bad() && !IS.fail() && "SPIRV stream fails"); M.add(Entry); return Entry; } void SPIRVDecoder::validate()const { IGC_ASSERT(OpCode != OpNop && "Invalid op code"); IGC_ASSERT(WordCount && "Invalid word count"); IGC_ASSERT(!IS.bad() && "Bad iInput stream"); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVStream.h000066400000000000000000000121111363533017100263100ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVStream.h - Class to represent a SPIR-V Stream --------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines Word class for SPIR-V. /// //===----------------------------------------------------------------------===// #ifndef SPIRVSTREAM_H #define SPIRVSTREAM_H #include "SPIRVDebug.h" #include "SPIRVModule.h" #include "SPIRVExtInst.h" #include #include #include #include #include #include namespace spv{ class SPIRVFunction; class SPIRVBasicBlock; class SPIRVDecoder { public: SPIRVDecoder(std::istream& InputStream, SPIRVModule& Module) :IS(InputStream), M(Module), WordCount(0), OpCode(OpNop), Scope(NULL){} SPIRVDecoder(std::istream& InputStream, SPIRVFunction& F); SPIRVDecoder(std::istream& InputStream, SPIRVBasicBlock &BB); void setScope(SPIRVEntry *); bool getWordCountAndOpCode(); SPIRVEntry *getEntry(); void validate()const; std::istream &IS; SPIRVModule &M; SPIRVWord WordCount; Op OpCode; SPIRVEntry *Scope; // A function or basic block }; template const SPIRVDecoder& DecodeBinary(const SPIRVDecoder& I, T &V); template const SPIRVDecoder& operator>>(const SPIRVDecoder& I, T &V) { return DecodeBinary(I, V); } template const SPIRVDecoder& operator>>(const SPIRVDecoder& I, T *&P) { SPIRVId Id; I >> Id; P = static_cast(I.M.getEntry(Id)); return I; } template const SPIRVDecoder& operator>>(const SPIRVDecoder& Decoder, const std::pair &Range) { for (IterTy I = Range.first, E = Range.second; I != E; ++I) Decoder >> *I; return Decoder; } template const SPIRVDecoder& operator>>(const SPIRVDecoder& I, std::vector &V) { for (size_t i = 0, e = V.size(); i != e; ++i) I >> V[i]; return I; } #define SPIRV_DEC_DEC(Type) \ const SPIRVDecoder& operator>>(const SPIRVDecoder& I, Type &V); SPIRV_DEC_DEC(Op) SPIRV_DEC_DEC(Decoration) SPIRV_DEC_DEC(OCLExtOpKind) SPIRV_DEC_DEC(OCLExtOpDbgKind) const SPIRVDecoder& operator>>(const SPIRVDecoder&I, std::string& Str); } // namespace spv #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVType.cpp000066400000000000000000000226771363533017100263530ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVtype.cpp - Class to represent a SPIR-V type ----------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements the types defined in SPIRV spec with op codes. /// //===----------------------------------------------------------------------===// #include "SPIRVType.h" #include "SPIRVDecorate.h" #include "SPIRVValue.h" #include "Probe.h" namespace spv{ SPIRVType* SPIRVType::getArrayElementType() const { IGC_ASSERT(OpCode == OpTypeArray && "Not array type"); return static_cast(this)->getElementType(); } uint64_t SPIRVType::getArrayLength() const { IGC_ASSERT(OpCode == OpTypeArray && "Not array type"); return static_cast(this)->getLength()-> getZExtIntValue(); } SPIRVWord SPIRVType::getBitWidth() const { if (isTypeVector()) return getVectorComponentType()->getBitWidth(); if (isTypeBool()) return 1; return isTypeInt()? getIntegerBitWidth() : getFloatBitWidth(); } SPIRVWord SPIRVType::getFloatBitWidth()const { IGC_ASSERT(OpCode == OpTypeFloat && "Not an integer type"); return static_cast(this)->getBitWidth(); } SPIRVWord SPIRVType::getIntegerBitWidth()const { IGC_ASSERT((OpCode == OpTypeInt || OpCode == OpTypeBool) && "Not an integer type"); if (isTypeBool()) return 1; return static_cast(this)->getBitWidth(); } SPIRVType * SPIRVType::getFunctionReturnType() const { IGC_ASSERT(OpCode == OpTypeFunction); return static_cast(this)->getReturnType(); } SPIRVType * SPIRVType::getPointerElementType()const { IGC_ASSERT(OpCode == OpTypePointer && "Not a pointer type"); return static_cast(this)->getElementType(); } SPIRVStorageClassKind SPIRVType::getPointerStorageClass() const { IGC_ASSERT(OpCode == OpTypePointer && "Not a pointer type"); return static_cast(this)->getStorageClass(); } SPIRVType* SPIRVType::getStructMemberType(size_t Index) const { IGC_ASSERT(OpCode == OpTypeStruct && "Not struct type"); return static_cast(this)->getMemberType(Index); } SPIRVWord SPIRVType::getStructMemberCount() const { IGC_ASSERT(OpCode == OpTypeStruct && "Not struct type"); return static_cast(this)->getMemberCount(); } SPIRVWord SPIRVType::getVectorComponentCount() const { IGC_ASSERT(OpCode == OpTypeVector && "Not vector type"); return static_cast(this)->getComponentCount(); } SPIRVType* SPIRVType::getVectorComponentType() const { IGC_ASSERT(OpCode == OpTypeVector && "Not vector type"); return static_cast(this)->getComponentType(); } bool SPIRVType::isTypeVoid() const { return OpCode == OpTypeVoid; } bool SPIRVType::isTypeArray() const { return OpCode == OpTypeArray; } bool SPIRVType::isTypeBool()const { return OpCode == OpTypeBool; } bool SPIRVType::isTypeComposite() const { return isTypeVector() || isTypeArray() || isTypeStruct(); } bool SPIRVType::isTypeFloat(unsigned Bits)const { return isType(this, Bits); } bool SPIRVType::isTypeOCLImage()const { return isTypeImage() && static_cast(this)-> isOCLImage(); } bool SPIRVType::isTypePipe()const { return OpCode == OpTypePipe; } bool SPIRVType::isTypeReserveId() const { return OpCode == OpTypeReserveId; } bool SPIRVType::isTypeInt(unsigned Bits)const { return isType(this, Bits); } bool SPIRVType::isTypePointer()const { return OpCode == OpTypePointer; } bool SPIRVType::isTypeOpaque()const { return OpCode == OpTypeOpaque; } bool SPIRVType::isTypeEvent()const { return OpCode == OpTypeEvent; } bool SPIRVType::isTypeDeviceEvent()const { return OpCode == OpTypeDeviceEvent; } bool SPIRVType::isTypeSampler()const { return OpCode == OpTypeSampler; } bool SPIRVType::isTypeImage()const { return OpCode == OpTypeImage; } bool SPIRVType::isTypeSampledImage() const { return OpCode == OpTypeSampledImage; } bool SPIRVType::isTypeVmeImageINTEL() const { return OpCode == OpTypeVmeImageINTEL; } bool SPIRVType::isTypeSubgroupAvcINTEL() const { return isSubgroupAvcINTELTypeOpCode(OpCode); } bool SPIRVType::isTypeStruct() const { return OpCode == OpTypeStruct; } bool SPIRVType::isTypeVector() const { return OpCode == OpTypeVector; } bool SPIRVType::isTypeNamedBarrier() const { return OpCode == OpTypeNamedBarrier; } bool SPIRVType::isTypeQueue() const { return OpCode == OpTypeQueue; } bool SPIRVType::isTypeVectorBool() const { return isTypeVector() && getVectorComponentType()->isTypeBool(); } bool SPIRVType::isTypeVectorInt() const { return isTypeVector() && getVectorComponentType()->isTypeInt(); } bool SPIRVType::isTypeVectorFloat() const { return isTypeVector() && getVectorComponentType()->isTypeFloat(); } bool SPIRVType::isTypeVectorOrScalarBool() const { return isTypeBool() || isTypeVectorBool(); } bool SPIRVType::isTypeVectorOrScalarInt() const { return isTypeInt() || isTypeVectorInt(); } bool SPIRVType::isTypeVectorOrScalarFloat() const { return isTypeFloat() || isTypeVectorFloat(); } void SPIRVTypeStruct::decode(std::istream &I) { auto Decoder = getDecoder(I); Decoder >> Id; for (size_t i = 0, e = MemberTypeVec.size(); i != e; ++i) { SPIRVId currId; Decoder >> currId; if (Decoder.M.exist(currId)) { MemberTypeVec[i] = static_cast(Decoder.M.getEntry(currId)); } else { MemberTypeVec[i] = nullptr; Decoder.M.addUnknownStructField(this, i, currId); } } } bool SPIRVTypeStruct::isPacked() const { return hasDecorate(DecorationCPacked); } void SPIRVTypeStruct::setPacked(bool Packed) { if (Packed) addDecorate(new SPIRVDecorate(DecorationCPacked, this)); else eraseDecorate(DecorationCPacked); } SPIRVTypeArray::SPIRVTypeArray(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheElemType, SPIRVConstant* TheLength) :SPIRVType(M, 4, OpTypeArray, TheId), ElemType(TheElemType), Length(TheLength->getId()){ validate(); } void SPIRVTypeArray::validate()const { SPIRVEntry::validate(); ElemType->validate(); IGC_ASSERT(getValue(Length)->getType()->isTypeInt() && get(Length)->getZExtIntValue() > 0); } SPIRVConstant* SPIRVTypeArray::getLength() const { return get(Length); } _SPIRV_IMP_DEC3(SPIRVTypeArray, Id, ElemType, Length) } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVType.h000066400000000000000000000602531363533017100260100ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVType.h - Class to represent a SPIR-V Type ------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines the types defined in SPIRV spec with op codes. /// /// The name of the SPIR-V types follow the op code name in the spec, e.g. /// SPIR-V type with op code name OpTypeInt is named as SPIRVTypeInt. This is /// for readability and ease of using macro to handle types. /// //===----------------------------------------------------------------------===// #ifndef SPIRVTYPE_HPP_ #define SPIRVTYPE_HPP_ #include "SPIRVEntry.h" #include "SPIRVStream.h" #include #include #include #include #include "Probe.h" namespace spv{ class SPIRVType: public SPIRVEntry { public: // Complete constructor SPIRVType(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVId TheId) :SPIRVEntry(M, TheWordCount, TheOpCode, TheId){} // Incomplete constructor SPIRVType(Op TheOpCode):SPIRVEntry(TheOpCode){} SPIRVType *getArrayElementType() const; uint64_t getArrayLength() const; unsigned getBitWidth() const; unsigned getFloatBitWidth() const; SPIRVType *getFunctionReturnType() const; unsigned getIntegerBitWidth() const; SPIRVType *getPointerElementType() const; SPIRVStorageClassKind getPointerStorageClass() const; SPIRVType *getStructMemberType(size_t) const; SPIRVWord getStructMemberCount() const; SPIRVWord getVectorComponentCount() const; SPIRVType *getVectorComponentType() const; bool isTypeVoid() const; bool isTypeArray() const; bool isTypeBool() const; bool isTypeComposite() const; bool isTypeEvent() const; bool isTypeDeviceEvent() const; bool isTypeReserveId() const; bool isTypeFloat(unsigned Bits = 0) const; bool isTypeImage() const; bool isTypeSampledImage() const; bool isTypeVmeImageINTEL() const; bool isTypeSubgroupAvcINTEL() const; bool isTypeOCLImage() const; bool isTypePipe()const; bool isTypeInt(unsigned Bits = 0) const; bool isTypeNamedBarrier() const; bool isTypeQueue() const; bool isTypeOpaque() const; bool isTypePointer() const; bool isTypeSampler() const; bool isTypeStruct() const; bool isTypeVector() const; bool isTypeVectorInt() const; bool isTypeVectorFloat() const; bool isTypeVectorBool() const; bool isTypeVectorOrScalarInt() const; bool isTypeVectorOrScalarFloat() const; bool isTypeVectorOrScalarBool() const; }; class SPIRVTypeVoid:public SPIRVType { public: // Complete constructor SPIRVTypeVoid(SPIRVModule *M, SPIRVId TheId) :SPIRVType(M, 2, OpTypeVoid, TheId){} // Incomplete constructor SPIRVTypeVoid():SPIRVType(OpTypeVoid){} protected: _SPIRV_DEF_DEC1(Id) }; class SPIRVTypeBool:public SPIRVType { public: // Complete constructor SPIRVTypeBool(SPIRVModule *M, SPIRVId TheId) :SPIRVType(M, 2, OpTypeBool, TheId){} // Incomplete constructor SPIRVTypeBool():SPIRVType(OpTypeBool){} protected: _SPIRV_DEF_DEC1(Id) }; class SPIRVTypeInt:public SPIRVType { public: static const Op OC = OpTypeInt; // Complete constructor SPIRVTypeInt(SPIRVModule *M, SPIRVId TheId, unsigned TheBitWidth, bool ItIsSigned) :SPIRVType(M, 4, OC , TheId), BitWidth(TheBitWidth), IsSigned(ItIsSigned){ validate(); } // Incomplete constructor SPIRVTypeInt():SPIRVType(OC), BitWidth(0), IsSigned(false){} unsigned getBitWidth() const { return BitWidth;} bool isSigned() const { return IsSigned;} protected: _SPIRV_DEF_DEC3(Id, BitWidth, IsSigned) void validate()const { SPIRVEntry::validate(); IGC_ASSERT_EXIT(BitWidth > 1 && BitWidth <= 64 && "Invalid bit width"); } private: unsigned BitWidth; // Bit width bool IsSigned; // Whether it is signed }; class SPIRVTypeFloat:public SPIRVType { public: static const Op OC = OpTypeFloat; // Complete constructor SPIRVTypeFloat(SPIRVModule *M, SPIRVId TheId, unsigned TheBitWidth) :SPIRVType(M, 3, OC, TheId), BitWidth(TheBitWidth){} // Incomplete constructor SPIRVTypeFloat():SPIRVType(OC), BitWidth(0){} unsigned getBitWidth() const { return BitWidth;} protected: _SPIRV_DEF_DEC2(Id, BitWidth) void validate()const { SPIRVEntry::validate(); IGC_ASSERT_EXIT(BitWidth >= 16 && BitWidth <= 64 && "Invalid bit width"); } private: unsigned BitWidth; // Bit width }; class SPIRVTypePointer:public SPIRVType { public: // Complete constructor SPIRVTypePointer(SPIRVModule *M, SPIRVId TheId, SPIRVStorageClassKind TheStorageClass, SPIRVType *ElementType) :SPIRVType(M, 4, OpTypePointer, TheId), StorageClass(TheStorageClass), ElemType(ElementType){ validate(); } // Incomplete constructor SPIRVTypePointer():SPIRVType(OpTypePointer), StorageClass(SPIRVStorageClassKind::StorageClassPrivateGlobal), ElemType(NULL){} SPIRVType *getElementType() const { return ElemType;} SPIRVStorageClassKind getStorageClass() const { return StorageClass;} CapVec getRequiredCapability() const { auto Cap = getVec(SPIRVCapabilityKind::CapabilityAddresses); if (ElemType->isTypeFloat(16)) Cap.push_back(SPIRVCapabilityKind::CapabilityFloat16Buffer); Cap.push_back(getCapability(StorageClass)); return Cap; } protected: _SPIRV_DEF_DEC3(Id, StorageClass, ElemType) void validate()const { SPIRVEntry::validate(); ElemType->validate(); IGC_ASSERT(isValid(StorageClass)); } private: SPIRVStorageClassKind StorageClass; // Storage Class SPIRVType *ElemType; // Element Type }; class SPIRVTypeVector:public SPIRVType { public: // Complete constructor SPIRVTypeVector(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheCompType, SPIRVWord TheCompCount) :SPIRVType(M, 4, OpTypeVector, TheId), CompType(TheCompType), CompCount(TheCompCount){ validate(); } // Incomplete constructor SPIRVTypeVector():SPIRVType(OpTypeVector), CompType(nullptr), CompCount(0){} SPIRVType *getComponentType() const { return CompType;} SPIRVWord getComponentCount() const { return CompCount;} bool isValidIndex(SPIRVWord Index) const { return Index < CompCount;} CapVec getRequiredCapability() const { if (CompCount > 8) return getVec(SPIRVCapabilityKind::CapabilityVector16); return CapVec(); } protected: _SPIRV_DEF_DEC3(Id, CompType, CompCount) void validate()const { SPIRVEntry::validate(); CompType->validate(); IGC_ASSERT(CompCount == 2 || CompCount == 3 || CompCount == 4 || CompCount == 8 || CompCount == 16); } private: SPIRVType *CompType; // Component Type SPIRVWord CompCount; // Component Count }; class SPIRVTypeArray:public SPIRVType { public: // Complete constructor SPIRVTypeArray(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheElemType, SPIRVConstant* TheLength); // Incomplete constructor SPIRVTypeArray():SPIRVType(OpTypeArray), ElemType(nullptr), Length(SPIRVID_INVALID){} SPIRVType *getElementType() const { return ElemType;} SPIRVConstant *getLength() const; protected: _SPIRV_DCL_DEC void validate()const; private: SPIRVType *ElemType; // Element Type SPIRVId Length; // Array Length }; class SPIRVTypeOpaque:public SPIRVType { public: // Complete constructor SPIRVTypeOpaque(SPIRVModule *M, SPIRVId TheId, const std::string& TheName) :SPIRVType(M, 2 + getSizeInWords(TheName), OpTypeOpaque, TheId) { Name = TheName; validate(); } // Incomplete constructor SPIRVTypeOpaque():SPIRVType(OpTypeOpaque){} protected: _SPIRV_DEF_DEC2(Id, Name) void validate()const { SPIRVEntry::validate(); } }; struct SPIRVTypeImageDescriptor { SPIRVImageDimKind Dim; SPIRVWord Depth; SPIRVWord Arrayed; SPIRVWord MS; SPIRVWord Sampled; SPIRVWord Format; static std::tuple, SPIRVWord> getAsTuple (const SPIRVTypeImageDescriptor &Desc) { return std::make_tuple(std::make_tuple(Desc.Dim, Desc.Depth, Desc.Arrayed, Desc.MS, Desc.Sampled), Desc.Format); } SPIRVTypeImageDescriptor():Dim(Dim1D), Depth(0), Arrayed(0), MS(0), Sampled(0), Format(0){} SPIRVTypeImageDescriptor(SPIRVImageDimKind Dim, SPIRVWord Cont, SPIRVWord Arr, SPIRVWord Comp, SPIRVWord Mult, SPIRVWord F):Dim(Dim), Depth(Cont), Arrayed(Arr), MS(Comp), Sampled(Mult), Format(F){} }; template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,...) {SPIRVTypeImageDescriptor S(__VA_ARGS__); \ add(#x, S);} _SPIRV_OP(image1d_t, Dim1D, 0, 0, 0, 0, 0) _SPIRV_OP(image1d_buffer_t, DimBuffer, 0, 0, 0, 0, 0) _SPIRV_OP(image1d_array_t, Dim1D, 0, 1, 0, 0, 0) _SPIRV_OP(image2d_t, Dim2D, 0, 0, 0, 0, 0) _SPIRV_OP(image2d_array_t, Dim2D, 0, 1, 0, 0, 0) _SPIRV_OP(image2d_depth_t, Dim2D, 1, 0, 0, 0, 0) _SPIRV_OP(image2d_array_depth_t, Dim2D, 1, 1, 0, 0, 0) _SPIRV_OP(image2d_msaa_t, Dim2D, 0, 0, 1, 0, 0) _SPIRV_OP(image2d_array_msaa_t, Dim2D, 0, 1, 1, 0, 0) _SPIRV_OP(image2d_msaa_depth_t, Dim2D, 1, 0, 1, 0, 0) _SPIRV_OP(image2d_array_msaa_depth_t, Dim2D, 1, 1, 1, 0, 0) _SPIRV_OP(image3d_t, Dim3D, 0, 0, 0, 0, 0) #undef _SPIRV_OP } typedef SPIRVMap OCLSPIRVImageTypeMap; // Comparision function required to use the struct as map key. inline bool operator<(const SPIRVTypeImageDescriptor &A, const SPIRVTypeImageDescriptor &B){ return SPIRVTypeImageDescriptor::getAsTuple(A) < SPIRVTypeImageDescriptor::getAsTuple(B); } class SPIRVTypeImage:public SPIRVType { public: const static Op OC = OpTypeImage; const static SPIRVWord FixedWC = 9; SPIRVTypeImage(SPIRVModule *M, SPIRVId TheId, SPIRVId TheSampledType, const SPIRVTypeImageDescriptor &TheDesc) :SPIRVType(M, FixedWC, OC, TheId), SampledType(TheSampledType), Desc(TheDesc){ validate(); } SPIRVTypeImage(SPIRVModule *M, SPIRVId TheId, SPIRVId TheSampledType, const SPIRVTypeImageDescriptor &TheDesc, SPIRVAccessQualifierKind TheAcc) :SPIRVType(M, FixedWC + 1, OC, TheId), SampledType(TheSampledType), Desc(TheDesc){ Acc.push_back(TheAcc); validate(); } SPIRVTypeImage():SPIRVType(OC), SampledType(SPIRVID_INVALID), Desc(DimCount, SPIRVWORD_MAX, SPIRVWORD_MAX, SPIRVWORD_MAX, SPIRVWORD_MAX, SPIRVWORD_MAX){ } const SPIRVTypeImageDescriptor &getDescriptor()const { return Desc; } bool isOCLImage() const { return Desc.Sampled == 0 /* Only known at runtime */ && Desc.Format == ImageFormatUnknown; } bool hasAccessQualifier() const { return !Acc.empty();} SPIRVAccessQualifierKind getAccessQualifier() const { // Play it safe, if unspecified assume it is read write. return hasAccessQualifier() ? Acc[0] : AccessQualifierReadWrite; } CapVec getRequiredCapability() const { CapVec CV; CV.push_back(SPIRVCapabilityKind::CapabilityImageBasic); if (Acc.size() > 0 && Acc[0] == AccessQualifierReadWrite) CV.push_back(SPIRVCapabilityKind::CapabilityImageReadWrite); if (Desc.MS) CV.push_back(SPIRVCapabilityKind::CapabilityImageMipmap); return CV; } protected: _SPIRV_DEF_DEC9(Id, SampledType, Desc.Dim, Desc.Depth, Desc.Arrayed, Desc.MS, Desc.Sampled, Desc.Format, Acc) // The validation assumes OpenCL image or sampler type. void validate()const { IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == FixedWC + Acc.size()); IGC_ASSERT(Desc.Dim <= 5); IGC_ASSERT(Desc.Depth <= 1); IGC_ASSERT(Desc.Arrayed <= 1); IGC_ASSERT(Desc.MS <= 1); IGC_ASSERT(Desc.Sampled == 0); // For OCL only IGC_ASSERT(Desc.Format == ImageFormatUnknown); // For OCL only IGC_ASSERT(Acc.size() <= 1); } void setWordCount(SPIRVWord TheWC) { WordCount = TheWC; Acc.resize(WordCount - FixedWC); } private: SPIRVId SampledType; SPIRVTypeImageDescriptor Desc; std::vector Acc; }; class SPIRVTypeSampler:public SPIRVType { public: const static Op OC = OpTypeSampler; const static SPIRVWord FixedWC = 2; SPIRVTypeSampler(SPIRVModule *M, SPIRVId TheId) :SPIRVType(M, FixedWC, OC, TheId){ validate(); } SPIRVTypeSampler():SPIRVType(OC){ } protected: _SPIRV_DEF_DEC1(Id) void validate()const { IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == FixedWC); } }; class SPIRVTypeSampledImage:public SPIRVType { public: const static Op OC = OpTypeSampledImage; const static SPIRVWord FixedWC = 3; SPIRVTypeSampledImage(SPIRVModule *M, SPIRVId TheId, SPIRVTypeImage *TheImgTy) :SPIRVType(M, FixedWC, OC, TheId), ImgTy(TheImgTy){ validate(); } SPIRVTypeSampledImage():SPIRVType(OC), ImgTy(nullptr){ } const SPIRVTypeImage *getImageType() const { return ImgTy; } void setImageType(SPIRVTypeImage *TheImgTy) { ImgTy = TheImgTy; } protected: SPIRVTypeImage *ImgTy; _SPIRV_DEF_DEC2(Id, ImgTy) void validate()const { IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == FixedWC); IGC_ASSERT(ImgTy && ImgTy->isTypeImage()); } }; class SPIRVTypeStruct:public SPIRVType { public: // Complete constructor SPIRVTypeStruct(SPIRVModule *M, SPIRVId TheId, const std::vector &TheMemberTypes, const std::string &TheName) :SPIRVType(M, 2 + TheMemberTypes.size(), OpTypeStruct, TheId), MemberTypeVec(TheMemberTypes){ Name = TheName; validate(); } // Incomplete constructor SPIRVTypeStruct():SPIRVType(OpTypeStruct){} SPIRVWord getMemberCount() const { return MemberTypeVec.size();} SPIRVType *getMemberType(size_t I) const { return MemberTypeVec[I];} void setMemberType(size_t I, SPIRVType* pTy) { MemberTypeVec[I] = pTy; } bool isPacked() const; void setPacked(bool Packed); protected: _SPIRV_DCL_DEC void setWordCount(SPIRVWord WordCount) { MemberTypeVec.resize(WordCount - 2);} void validate()const { SPIRVEntry::validate(); } private: std::vector MemberTypeVec; // Member Types }; class SPIRVTypeFunction:public SPIRVType { public: // Complete constructor SPIRVTypeFunction(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheReturnType, const std::vector &TheParameterTypes) :SPIRVType(M, 3 + TheParameterTypes.size(), OpTypeFunction, TheId), ReturnType(TheReturnType), ParamTypeVec(TheParameterTypes){ validate(); } // Incomplete constructor SPIRVTypeFunction():SPIRVType(OpTypeFunction), ReturnType(NULL){} SPIRVType *getReturnType() const { return ReturnType;} SPIRVWord getNumParameters() const { return ParamTypeVec.size();} SPIRVType *getParameterType(unsigned I) const { return ParamTypeVec[I];} protected: _SPIRV_DEF_DEC3(Id, ReturnType, ParamTypeVec) void setWordCount(SPIRVWord WordCount) { SPIRVType::setWordCount(WordCount); ParamTypeVec.resize(WordCount - 3); } void validate()const { SPIRVEntry::validate(); ReturnType->validate(); for (auto T:ParamTypeVec) T->validate(); } private: SPIRVType *ReturnType; // Return Type std::vector ParamTypeVec; // Parameter Types }; class SPIRVTypeOpaqueGeneric:public SPIRVType { public: // Complete constructor SPIRVTypeOpaqueGeneric(Op TheOpCode, SPIRVModule *M, SPIRVId TheId) :SPIRVType(M, 2, TheOpCode, TheId){ validate(); } // Incomplete constructor SPIRVTypeOpaqueGeneric(Op TheOpCode):SPIRVType(TheOpCode), Opn(SPIRVID_INVALID) {} SPIRVValue *getOperand() { return getValue(Opn); } protected: _SPIRV_DEF_DEC1(Id) void validate()const { SPIRVEntry::validate(); } SPIRVId Opn; }; template class SPIRVOpaqueGenericType:public SPIRVTypeOpaqueGeneric { public: // Complete constructor SPIRVOpaqueGenericType(SPIRVModule *M, SPIRVId TheId) :SPIRVTypeOpaqueGeneric(TheOpCode, M, TheId){} // Incomplete constructor SPIRVOpaqueGenericType():SPIRVTypeOpaqueGeneric(TheOpCode){} }; #define _SPIRV_OP(x) typedef SPIRVOpaqueGenericType SPIRVType##x; _SPIRV_OP(Event) _SPIRV_OP(DeviceEvent) _SPIRV_OP(ReserveId) _SPIRV_OP(Queue) #undef _SPIRV_OP class SPIRVTypePipe :public SPIRVType { public: // Complete constructor SPIRVTypePipe(SPIRVModule *M, SPIRVId TheId, SPIRVAccessQualifierKind AccessQual = AccessQualifierReadOnly) :SPIRVType(M, 3, OpTypePipe, TheId), AccessQualifier(AccessQual){ validate(); } // Incomplete constructor SPIRVTypePipe() :SPIRVType(OpTypePipe), AccessQualifier(SPIRVAccessQualifierKind::AccessQualifierReadOnly){} SPIRVAccessQualifierKind getAccessQualifier() const { return AccessQualifier; } void setPipeAcessQualifier(SPIRVAccessQualifierKind AccessQual) { AccessQualifier = AccessQual; IGC_ASSERT(isValid(AccessQualifier)); } CapVec getRequiredCapability() const { return getVec(SPIRVCapabilityKind::CapabilityPipes); } protected: _SPIRV_DEF_DEC2(Id, AccessQualifier) void validate()const { SPIRVEntry::validate(); } private: SPIRVAccessQualifierKind AccessQualifier; // Access Qualifier }; class SPIRVTypePipeStorage : public SPIRVType { public: // Incomplete constructor SPIRVTypePipeStorage() : SPIRVType(OpTypePipeStorage) {} CapVec getRequiredCapability() const { return getVec(SPIRVCapabilityKind::CapabilityPipeStorage); } private: _SPIRV_DEF_DEC1(Id) }; class SPIRVTypeNamedBarrier :public SPIRVType { public: // Incomplete constructor SPIRVTypeNamedBarrier() :SPIRVType(OpTypeNamedBarrier){} CapVec getRequiredCapability() const { return getVec(SPIRVCapabilityKind::CapabilityNamedBarrier); } protected: _SPIRV_DEF_DEC1(Id) void validate()const { SPIRVEntry::validate(); } }; template bool isType(const T1 *Ty, unsigned Bits = 0) { bool Is = Ty->getOpCode() == T2::OC; if (Bits == 0) return Is; return static_cast(Ty)->getBitWidth() == Bits; } // SPV_INTEL_device_side_avc_motion_estimation extension types class SPIRVTypeVmeImageINTEL : public SPIRVType { public: const static Op OC = OpTypeVmeImageINTEL; const static SPIRVWord FixedWC = 3; SPIRVTypeVmeImageINTEL( SPIRVModule *M, SPIRVId TheId, SPIRVTypeImage *TheImgTy) : SPIRVType(M, FixedWC, OC, TheId), ImgTy(TheImgTy) { validate(); } SPIRVTypeVmeImageINTEL() : SPIRVType(OC), ImgTy(nullptr) {} const SPIRVTypeImage *getImageType() const { return ImgTy; } void setImageType(SPIRVTypeImage *TheImgTy) { ImgTy = TheImgTy; } virtual std::vector getNonLiteralOperands() const { return std::vector(1, ImgTy); } CapVec getRequiredCapability() const { return getVec(CapabilitySubgroupAvcMotionEstimationINTEL); } protected: SPIRVTypeImage * ImgTy; _SPIRV_DEF_DEC2(Id, ImgTy) void validate()const { IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == FixedWC); IGC_ASSERT(ImgTy && ImgTy->isTypeImage()); } }; class SPIRVTypeSubgroupINTEL; template<> inline void SPIRVMap::init() { #define _SPIRV_OP(x,y) \ add("struct.intel_sub_group_avc_"#x, OpTypeAvc##y##INTEL); _SPIRV_OP(mce_payload_t, McePayload) _SPIRV_OP(mce_result_t, MceResult) _SPIRV_OP(sic_payload_t, SicPayload) _SPIRV_OP(sic_result_t, SicResult) _SPIRV_OP(ime_result_single_reference_streamout_t, ImeResultSingleReferenceStreamout) _SPIRV_OP(ime_result_dual_reference_streamout_t, ImeResultDualReferenceStreamout) _SPIRV_OP(ime_single_reference_streamin_t, ImeSingleReferenceStreamin) _SPIRV_OP(ime_dual_reference_streamin_t, ImeDualReferenceStreamin) _SPIRV_OP(ime_payload_t, ImePayload) _SPIRV_OP(ime_result_t, ImeResult) _SPIRV_OP(ref_payload_t, RefPayload) _SPIRV_OP(ref_result_t, RefResult); #undef _SPIRV_OP } typedef SPIRVMap OCLSubgroupINTELTypeOpCodeMap; class SPIRVTypeSubgroupAvcINTEL : public SPIRVType { public: // Complete constructor SPIRVTypeSubgroupAvcINTEL(Op TheOpCode, SPIRVModule *M, SPIRVId TheId) : SPIRVType(M, 2, TheOpCode, TheId) { validate(); } // Incomplete constructor SPIRVTypeSubgroupAvcINTEL(Op TheOpCode) : SPIRVType(TheOpCode), Opn(SPIRVID_INVALID) {} CapVec getRequiredCapability() const { return getVec(CapabilitySubgroupAvcMotionEstimationINTEL); } SPIRVValue *getOperand() { return getValue(Opn); } protected: _SPIRV_DEF_DEC1(Id) void validate() const { SPIRVEntry::validate(); } SPIRVId Opn; }; template class SPIRVSubgroupAvcINTELType : public SPIRVTypeSubgroupAvcINTEL { public: // Complete constructor SPIRVSubgroupAvcINTELType(SPIRVModule *M, SPIRVId TheId) : SPIRVTypeSubgroupAvcINTEL(TheOpCode, M, TheId) {} // Incomplete constructor SPIRVSubgroupAvcINTELType() : SPIRVTypeSubgroupAvcINTEL(TheOpCode) {} }; #define _SPIRV_OP(x) \ typedef SPIRVSubgroupAvcINTELType SPIRVType##x##INTEL; _SPIRV_OP(AvcMcePayload) _SPIRV_OP(AvcImePayload) _SPIRV_OP(AvcRefPayload) _SPIRV_OP(AvcSicPayload) _SPIRV_OP(AvcMceResult) _SPIRV_OP(AvcImeResult) _SPIRV_OP(AvcImeResultSingleReferenceStreamout) _SPIRV_OP(AvcImeResultDualReferenceStreamout) _SPIRV_OP(AvcImeSingleReferenceStreamin) _SPIRV_OP(AvcImeDualReferenceStreamin) _SPIRV_OP(AvcRefResult) _SPIRV_OP(AvcSicResult) #undef _SPIRV_OP } #endif // SPIRVTYPE_HPP_ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVUtil.h000066400000000000000000000231461363533017100260040ustar00rootroot00000000000000//===- SPIRVUtil.h - SPIR-V Utility Functions --------------------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines SPIR-V utility functions. /// //===----------------------------------------------------------------------===// #ifndef SPIRVUTIL_H_ #define SPIRVUTIL_H_ #include #include #include #include #include #include #include #include #include #include "Probe.h" namespace spv{ #define SPIRV_DEF_NAMEMAP(Type,MapType) \ typedef SPIRVMap MapType; \ inline MapType getNameMap(Type){ MapType MT; return MT;} // A bi-way map template struct SPIRVMap { public: typedef Ty1 KeyTy; typedef Ty2 ValueTy; // Initialize map entries void init(); static Ty2 map(Ty1 Key) { Ty2 Val; bool Found = find(Key, &Val); IGC_ASSERT(Found && "Invalid key"); return Val; } static Ty1 rmap(Ty2 Key) { Ty1 Val; bool Found = rfind(Key, &Val); IGC_ASSERT(Found && "Invalid key"); return Val; } static const SPIRVMap& getMap() { static const SPIRVMap Map(false); return Map; } static const SPIRVMap& getRMap() { static const SPIRVMap Map(true); return Map; } static void foreach(std::functionF) { for (auto &I:getMap().Map) F(I.first, I.second); } // For each key/value in the map executes function \p F. // If \p F returns false break the iteration. static void foreach_conditional(std::functionF) { for (auto &I:getMap().Map) { if (!F(I.first, I.second)) break; } } static bool find(Ty1 Key, Ty2 *Val = nullptr) { const SPIRVMap& Map = getMap(); typename MapTy::const_iterator Loc = Map.Map.find(Key); if(Loc == Map.Map.end()) return false; if (Val) *Val = Loc->second; return true; } static bool rfind(Ty2 Key, Ty1 *Val = nullptr) { const SPIRVMap& Map = getRMap(); typename RevMapTy::const_iterator Loc = Map.RevMap.find(Key); if (Loc == Map.RevMap.end()) return false; if (Val) *Val = Loc->second; return true; } SPIRVMap():IsReverse(false){} protected: SPIRVMap(bool Reverse):IsReverse(Reverse){ init(); } typedef std::map MapTy; typedef std::map RevMapTy; void add(Ty1 V1, Ty2 V2) { if (IsReverse) { RevMap[V2] = V1; return; } Map[V1] = V2; } MapTy Map; RevMapTy RevMap; bool IsReverse; }; inline std::vector getVec(const std::string &S, char Delim) { std::vector Strs; std::stringstream SS(S); std::string Item; while (std::getline(SS, Item, Delim)) Strs.push_back(Item); return Strs; } inline std::unordered_set getUnordSet(const std::string &S, char Delim = ' ') { std::unordered_set Strs; std::stringstream SS(S); std::string Item; while (std::getline(SS, Item, Delim)) Strs.insert(Item); return Strs; } inline std::set getSet(const std::string &S, char Delim = ' ') { std::set Strs; std::stringstream SS(S); std::string Item; while (std::getline(SS, Item, Delim)) Strs.insert(Item); return Strs; } template VT map(KT Key) { return SPIRVMap::map(Key); } template KT rmap(VT V) { return SPIRVMap::rmap(V); } template std::unordered_set map(const std::unordered_set &KSet) { VT V; std::unordered_set VSet; for (auto &I:KSet) if (SPIRVMap::find(I, &V)) VSet.insert(V); return VSet; } template std::set map(const std::set &KSet) { VT V; std::set VSet; for (auto &I:KSet) if (SPIRVMap::find(I, &V)) VSet.insert(V); return VSet; } template std::unordered_set rmap(const std::unordered_set &KSet) { KT V; std::unordered_set VSet; for (auto &I:KSet) if (SPIRVMap::rfind(I, &V)) VSet.insert(V); return VSet; } template std::set rmap(const std::set &KSet) { KT V; std::set VSet; for (auto &I:KSet) if (SPIRVMap::rfind(I, &V)) VSet.insert(V); return VSet; } template std::string getName(K Key) { std::string Name; if (SPIRVMap::find(Key, &Name)) return Name; return ""; } template bool getByName(const std::string &Name, K &Key) { return SPIRVMap::rfind(Name, &Key); } // Add a number as a string to a string template std::string concat(const std::string& s, const T& n) { std::stringstream ss; ss << s << n; return ss.str(); } inline std::string concat(const std::string &S1, const std::string &S2, char Delim = ' ') { std::string S; if (S1.empty()) S = S2; else if (!S2.empty()) S = S1 + Delim + S2; return S; } inline std::string operator+(const std::string& s, int n) { return concat(s, n); } inline std::string operator+(const std::string& s, unsigned n) { return concat(s, n); } template std::string getStr(const T &C, char Delim = ' ') { std::stringstream SS; bool First = true; for (auto &I:C) { if (!First) SS << Delim; else First = false; SS << I; } return SS.str(); } template unsigned mapBitMask(unsigned BM) { unsigned Res = 0; MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){ Res |= BM & (unsigned)K ? (unsigned)V : 0; }); return Res; } template unsigned rmapBitMask(unsigned BM) { unsigned Res = 0; MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){ Res |= BM & (unsigned)V ? (unsigned)K : 0; }); return Res; } // Get the number of words used for encoding a string literal in SPIRV inline unsigned getSizeInWords(const std::string& Str) { IGC_ASSERT(Str.length()/4 + 1 <= std::numeric_limits::max()); return static_cast(Str.length()/4 + 1); } inline std::string getString(std::vector::const_iterator Begin, std::vector::const_iterator End) { std::string Str = std::string(); for (auto I = Begin; I != End; ++I) { uint32_t Word = *I; for (unsigned J = 0u; J < 32u; J += 8u) { char Char = (char)((Word >> J) & 0xff); if (Char == '\0') return Str; Str += Char; } } return Str; } inline std::string getString(const std::vector &V) { return getString(V.cbegin(), V.cend()); } // if vector of Literals is expected to contain more than one Literal String inline std::vector getVecString(const std::vector &V) { std::vector Result; std::string Str; for (auto It = V.cbegin(); It < V.cend(); It += getSizeInWords(Str)) { Str.clear(); Str = getString(It, V.cend()); Result.push_back(Str); } return Result; } template inline std::vector getVec(T Op1) { std::vector V; V.push_back(Op1); return V; } template inline std::vector getVec(T Op1, T Op2) { std::vector V; V.push_back(Op1); V.push_back(Op2); return V; } template inline std::vector getVec(T Op1, T Op2, T Op3) { std::vector V; V.push_back(Op1); V.push_back(Op2); V.push_back(Op3); return V; } template inline std::vector getVec(T Op1, const std::vector &Ops2) { std::vector V; V.push_back(Op1); V.insert(V.end(), Ops2.begin(), Ops2.end()); return V; } template typename MapTy::mapped_type getOrInsert( MapTy &Map, typename MapTy::key_type Key, FuncTy Func){ typename MapTy::iterator Loc = Map.find(Key); if (Loc != Map.end()) return Loc->second; typename MapTy::mapped_type NF = Func(); Map[Key] = NF; return NF; } } #endif /* SPIRVUTIL_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVValue.cpp000066400000000000000000000070031363533017100264700ustar00rootroot00000000000000//===- SPIRVValue.cpp - Class to represent a SPIR-V Value --------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines the values defined in SPIR-V spec with op codes. /// /// The name of the SPIR-V values follow the op code name in the spec. /// This is for readability and ease of using macro to handle types. // //===----------------------------------------------------------------------===// #include "SPIRVValue.h" namespace spv{ void SPIRVValue::setAlignment(SPIRVWord A) { if (A == 0) { eraseDecorate(DecorationAlignment); return; } addDecorate(new SPIRVDecorate(DecorationAlignment, this, A)); } bool SPIRVValue::hasAlignment(SPIRVWord *Result)const { return hasDecorate(DecorationAlignment, 0, Result); } bool SPIRVValue::isVolatile()const { return hasDecorate(DecorationVolatile); } void SPIRVValue::setVolatile(bool IsVolatile) { if (!IsVolatile) { eraseDecorate(DecorationVolatile); return; } addDecorate(new SPIRVDecorate(DecorationVolatile, this)); } bool SPIRVValue::hasNoSignedWrap() const { return hasDecorate(DecorationNoSignedWrap); } void SPIRVValue::setNoSignedWrap(bool HasNoSignedWrap) { if (!HasNoSignedWrap) { eraseDecorate(DecorationNoSignedWrap); return; } addDecorate(new SPIRVDecorate(DecorationNoSignedWrap, this)); SPIRVDBG(spvdbgs() << "Set nsw " << " for obj " << Id << "\n") } bool SPIRVValue::hasNoUnsignedWrap() const { return hasDecorate(DecorationNoUnsignedWrap); } void SPIRVValue::setNoUnsignedWrap(bool HasNoUnsignedWrap) { if (!HasNoUnsignedWrap) { eraseDecorate(DecorationNoUnsignedWrap); return; } addDecorate(new SPIRVDecorate(DecorationNoUnsignedWrap, this)); SPIRVDBG(spvdbgs() << "Set nuw " << " for obj " << Id << "\n") } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/SPIRVValue.h000066400000000000000000000325101363533017100261360ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- SPIRVValue.h - Class to represent a SPIR-V Value ----------*- C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines the values defined in SPIR-V spec with op codes. /// /// The name of the SPIR-V values follow the op code name in the spec. /// This is for readability and ease of using macro to handle types. // //===----------------------------------------------------------------------===// #ifndef SPIRVVALUE_HPP_ #define SPIRVVALUE_HPP_ #include "SPIRVEntry.h" #include "SPIRVType.h" #include "SPIRVDecorate.h" #include "Probe.h" #include #include #include namespace spv{ class SPIRVValue: public SPIRVEntry { public: // Complete constructor for value with id and type SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVType *TheType, SPIRVId TheId) :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) { validate(); } // Complete constructor for value with type but without id SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVType *TheType) :SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) { setHasNoId(); validate(); } // Complete constructor for value with id but without type SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVId TheId) :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) { setHasNoType(); validate(); } // Complete constructor for value without id and type SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode) :SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) { setHasNoId(); setHasNoType(); validate(); } // Incomplete constructor SPIRVValue(Op TheOpCode):SPIRVEntry(TheOpCode), Type(NULL) {} bool hasType()const { return !(Attrib & SPIRVEA_NOTYPE);} SPIRVType *getType()const { IGC_ASSERT(hasType() && "value has no type"); return Type; } bool isVolatile()const; bool hasAlignment(SPIRVWord *Result=0)const; bool hasNoSignedWrap() const; bool hasNoUnsignedWrap() const; void setAlignment(SPIRVWord); void setVolatile(bool IsVolatile); void setNoSignedWrap(bool HasNoSignedWrap); void setNoUnsignedWrap(bool HasNoUnsignedWrap); void validate()const { SPIRVEntry::validate(); IGC_ASSERT((!hasType() || Type) && "Invalid type"); } void setType(SPIRVType *Ty) { Type = Ty; IGC_ASSERT(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction); if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction)) setHasType(); else setHasNoType(); } CapVec getRequiredCapability() const { CapVec CV; if (!hasType()) return CV; if (Type->isTypeFloat(16)) CV.push_back(SPIRVCapabilityKind::CapabilityFloat16); else if (Type->isTypeFloat(64)) CV.push_back(SPIRVCapabilityKind::CapabilityFloat64); else if (Type->isTypeInt(16)) CV.push_back(SPIRVCapabilityKind::CapabilityInt16); else if (Type->isTypeInt(64)) CV.push_back(SPIRVCapabilityKind::CapabilityInt64); return CV; } protected: void setHasNoType() { Attrib |= SPIRVEA_NOTYPE;} void setHasType() { Attrib &= ~SPIRVEA_NOTYPE;} SPIRVType *Type; // Value Type }; template class SPIRVConstantBase: public SPIRVValue { public: // Complete constructor for integer constant SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, uint64_t TheValue) :SPIRVValue(M, 0, OC, TheType, TheId){ Union.UInt64Val = TheValue; recalculateWordCount(); validate(); } // Complete constructor for float constant SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, float TheValue) :SPIRVValue(M, 0, OC, TheType, TheId){ Union.FloatVal = TheValue; recalculateWordCount(); validate(); } // Complete constructor for double constant SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, double TheValue) :SPIRVValue(M, 0, OC, TheType, TheId){ Union.DoubleVal = TheValue; recalculateWordCount(); validate(); } // Incomplete constructor SPIRVConstantBase():SPIRVValue(OC), NumWords(0){} uint64_t getZExtIntValue() const { return Union.UInt64Val;} float getFloatValue() const { return Union.FloatVal;} double getDoubleValue() const { return Union.DoubleVal;} bool isConstant() { return true; } protected: void recalculateWordCount() { NumWords = Type->getBitWidth()/32; if (NumWords < 1) NumWords = 1; WordCount = 3 + NumWords; } void validate() const { SPIRVValue::validate(); IGC_ASSERT_EXIT(NumWords >= 1 && NumWords <= 2 && "Invalid constant size"); } void setWordCount(SPIRVWord WordCount) { SPIRVValue::setWordCount(WordCount); NumWords = WordCount - 3; } void decode(std::istream &I) { getDecoder(I) >> Type >> Id; validate(); for (unsigned i = 0; i < NumWords; ++i) getDecoder(I) >> Union.Words[i]; } unsigned NumWords; union UnionType{ uint64_t UInt64Val; float FloatVal; double DoubleVal; SPIRVWord Words[2]; UnionType() { UInt64Val = 0; } } Union; }; typedef SPIRVConstantBase SPIRVConstant; typedef SPIRVConstantBase SPIRVSpecConstant; template class SPIRVConstantEmpty: public SPIRVValue { public: // Complete constructor SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) :SPIRVValue(M, 3, OC, TheType, TheId){ validate(); } // Incomplete constructor SPIRVConstantEmpty():SPIRVValue(OC){} protected: void validate() const { SPIRVValue::validate(); } _SPIRV_DEF_DEC2(Type, Id) }; template class SPIRVConstantBool: public SPIRVConstantEmpty { public: // Complete constructor SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) :SPIRVConstantEmpty(M, TheType, TheId){} // Incomplete constructor SPIRVConstantBool(){} protected: void validate() const { SPIRVConstantEmpty::validate(); IGC_ASSERT(this->Type->isTypeBool() && "Invalid type"); } }; typedef SPIRVConstantBool SPIRVConstantTrue; typedef SPIRVConstantBool SPIRVConstantFalse; typedef SPIRVConstantBool SPIRVSpecConstantTrue; typedef SPIRVConstantBool SPIRVSpecConstantFalse; class SPIRVConstantNull : public SPIRVConstantEmpty { public: // Complete constructor SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) : SPIRVConstantEmpty(M, TheType, TheId) { validate(); } // Incomplete constructor SPIRVConstantNull() {} protected: void validate() const override { SPIRVConstantEmpty::validate(); IGC_ASSERT((Type->isTypeInt() || Type->isTypeBool() || Type->isTypeFloat() || Type->isTypeComposite() || Type->isTypeOpaque() || Type->isTypeEvent() || Type->isTypePointer() || Type->isTypeReserveId() || Type->isTypeDeviceEvent() || (Type->isTypeSubgroupAvcINTEL())) && "Invalid type"); } }; class SPIRVUndef : public SPIRVConstantEmpty { public: // Incomplete constructor SPIRVUndef() {} protected: void validate() const { SPIRVConstantEmpty::validate(); } }; template class SPIRVConstantCompositeBase: public SPIRVValue { public: // Complete constructor for composite constant SPIRVConstantCompositeBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, const std::vector TheElements) :SPIRVValue(M, TheElements.size()+3, OC, TheType, TheId){ Elements = getIds(TheElements); validate(); } // Incomplete constructor SPIRVConstantCompositeBase():SPIRVValue(OC){} std::vector getElements()const { return getValues(Elements); } protected: void validate() const { SPIRVValue::validate(); for (auto &I:Elements) getValue(I)->validate(); } void setWordCount(SPIRVWord WordCount) { Elements.resize(WordCount - 3); } _SPIRV_DEF_DEC3(Type, Id, Elements) std::vector Elements; }; typedef SPIRVConstantCompositeBase SPIRVConstantComposite; typedef SPIRVConstantCompositeBase SPIRVSpecConstantComposite; class SPIRVConstantSampler: public SPIRVValue { public: const static Op OC = OpConstantSampler; const static SPIRVWord WC = 6; // Complete constructor SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, SPIRVWord TheAddrMode, SPIRVWord TheNormalized, SPIRVWord TheFilterMode) :SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode), Normalized(TheNormalized), FilterMode(TheFilterMode){ validate(); } // Incomplete constructor SPIRVConstantSampler() :SPIRVValue(OC), AddrMode(SPIRVSamplerAddressingModeKind::SamplerAddressingModeNone), Normalized(SPIRVWORD_MAX), FilterMode(SPIRVSamplerFilterModeKind::SamplerFilterModeNearest){} SPIRVWord getAddrMode() const { return AddrMode; } SPIRVWord getFilterMode() const { return FilterMode; } SPIRVWord getNormalized() const { return Normalized; } CapVec getRequiredCapability() const { return getVec(SPIRVCapabilityKind::CapabilityLiteralSampler); } protected: SPIRVWord AddrMode; SPIRVWord Normalized; SPIRVWord FilterMode; void validate() const { SPIRVValue::validate(); IGC_ASSERT(OpCode == OC); IGC_ASSERT(WordCount == WC); IGC_ASSERT(Type->isTypeSampler()); } _SPIRV_DEF_DEC5(Type, Id, AddrMode, Normalized, FilterMode) }; class SPIRVForward:public SPIRVValue, public SPIRVComponentExecutionModes { public: const static Op OC = OpForward; // Complete constructor SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId): SPIRVValue(TheModule, 0, OC, TheId){ if (TheTy) setType(TheTy); } SPIRVForward():SPIRVValue(OC) { IGC_ASSERT_EXIT(0 && "should never be called"); } _SPIRV_DEF_DEC1(Id) friend class SPIRVFunction; protected: void validate() const {} }; class SPIRVConstantPipeStorage : public SPIRVValue { public: static const Op OC = OpConstantPipeStorage; SPIRVConstantPipeStorage() : SPIRVValue(OC) {} uint32_t GetPacketSize() { return PacketSize; } uint32_t GetPacketAlignment() { return PacketAlignment; } uint32_t GetCapacity() { return Capacity; } private: _SPIRV_DEF_DEC5(Type, Id, PacketSize, PacketAlignment, Capacity) uint32_t PacketSize; uint32_t PacketAlignment; uint32_t Capacity; }; } #endif /* SPIRVVALUE_HPP_ */ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/SPIRV/libSPIRV/spirv.hpp000066400000000000000000000512061363533017100257440ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // Copyright (c) 2014-2015 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), // to deal in the Materials without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Materials, and to permit persons to whom the // Materials are furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Materials. // // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND // HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ // // THE MATERIALS ARE 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 AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS // IN THE MATERIALS. // This header is automatically generated by the same tool that creates // the Binary Section of the SPIR-V specification. // Enumeration tokens for SPIR-V, in various styles: // C, C++, C++11, JSON, Lua, Python // // - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL // - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL // - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL // - Lua will use tables, e.g.: spv.SourceLanguage.GLSL // - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] // // Some tokens act like mask values, which can be OR'd together, // while others are mutually exclusive. The mask-like ones have // "Mask" in their name, and a parallel enum that has the shift // amount (1 << x) for each corresponding enumerant. #ifndef spirv_H #define spirv_H namespace spv { typedef unsigned int Id; #define SPV_VERSION_1_0 100 #define SPV_VERSION_1_1 101 #define SPV_REVISION 1 static const unsigned int MagicNumber = 0x07230203; static const unsigned int Version = 0x00010100; static const unsigned int Revision = 1; static const unsigned int OpCodeMask = 0xffff; static const unsigned int WordCountShift = 16; enum SpvSourceLanguage { SpvSourceLanguageUnknown = 0, SpvSourceLanguageESSL = 1, SpvSourceLanguageGLSL = 2, SpvSourceLanguageOpenCL_C = 3, SpvSourceLanguageOpenCL_CPP = 4, }; enum ExecutionModel { ExecutionModelVertex = 0, ExecutionModelTessellationControl = 1, ExecutionModelTessellationEvaluation = 2, ExecutionModelGeometry = 3, ExecutionModelFragment = 4, ExecutionModelGLCompute = 5, ExecutionModelKernel = 6, ExecutionModelCount, /* internal use only */ }; enum AddressingModel { AddressingModelLogical = 0, AddressingModelPhysical32 = 1, AddressingModelPhysical64 = 2, AddressingModelCount /* internal use only */ }; enum MemoryModel { MemoryModelSimple = 0, MemoryModelGLSL450 = 1, MemoryModelOpenCL = 2, MemoryModelCount /* internal use only */ }; enum ExecutionMode { ExecutionModeInvocations = 0, ExecutionModeSpacingEqual = 1, ExecutionModeSpacingFractionalEven = 2, ExecutionModeSpacingFractionalOdd = 3, ExecutionModeVertexOrderCw = 4, ExecutionModeVertexOrderCcw = 5, ExecutionModePixelCenterInteger = 6, ExecutionModeOriginUpperLeft = 7, ExecutionModeOriginLowerLeft = 8, ExecutionModeEarlyFragmentTests = 9, ExecutionModePointMode = 10, ExecutionModeXfb = 11, ExecutionModeDepthReplacing = 12, /* No Enum for 13 */ ExecutionModeDepthGreater = 14, ExecutionModeDepthLess = 15, ExecutionModeDepthUnchanged = 16, ExecutionModeLocalSize = 17, ExecutionModeLocalSizeHint = 18, ExecutionModeInputPoints = 19, ExecutionModeInputLines = 20, ExecutionModeInputLinesAdjacency = 21, ExecutionModeInputTriangles = 22, ExecutionModeInputTrianglesAdjacency = 23, ExecutionModeInputQuads = 24, ExecutionModeInputIsolines = 25, ExecutionModeOutputVertices = 26, ExecutionModeOutputPoints = 27, ExecutionModeOutputLineStrip = 28, ExecutionModeOutputTriangleStrip = 29, ExecutionModeVecTypeHint = 30, ExecutionModeContractionOff = 31, /* No Enum for 32 */ ExecutionModeInitializer = 33, ExecutionModeFinalizer = 34, ExecutionModeSubgroupSize = 35, ExecutionModeSubgroupsPerWorkgroup = 36, ExecutionModeCount /* internal use only */ }; enum StorageClass { StorageClassUniformConstant = 0, StorageClassInput = 1, StorageClassUniform = 2, StorageClassOutput = 3, StorageClassWorkgroupLocal = 4, StorageClassWorkgroupGlobal = 5, StorageClassPrivateGlobal = 6, StorageClassFunction = 7, StorageClassGeneric = 8, StorageClassPushConstant = 9, StorageClassAtomicCounter = 10, StorageClassImage = 11, StorageClassCount /* internal use only */ }; enum Dim { Dim1D = 0, Dim2D = 1, Dim3D = 2, DimCube = 3, DimRect = 4, DimBuffer = 5, DimInputTarget = 6, DimCount /* internal use only */ }; enum SamplerAddressingMode { SamplerAddressingModeNone = 0, SamplerAddressingModeClampToEdge = 1, SamplerAddressingModeClamp = 2, SamplerAddressingModeRepeat = 3, SamplerAddressingModeRepeatMirrored = 4, }; enum SamplerFilterMode { SamplerFilterModeNearest = 0, SamplerFilterModeLinear = 1, }; enum ImageFormat { ImageFormatUnknown = 0, ImageFormatRgba32f = 1, ImageFormatRgba16f = 2, ImageFormatR32f = 3, ImageFormatRgba8 = 4, ImageFormatRgba8Snorm = 5, ImageFormatRg32f = 6, ImageFormatRg16f = 7, ImageFormatR11fG11fB10f = 8, ImageFormatR16f = 9, ImageFormatRgba16 = 10, ImageFormatRgb10A2 = 11, ImageFormatRg16 = 12, ImageFormatRg8 = 13, ImageFormatR16 = 14, ImageFormatR8 = 15, ImageFormatRgba16Snorm = 16, ImageFormatRg16Snorm = 17, ImageFormatRg8Snorm = 18, ImageFormatR16Snorm = 19, ImageFormatR8Snorm = 20, ImageFormatRgba32i = 21, ImageFormatRgba16i = 22, ImageFormatRgba8i = 23, ImageFormatR32i = 24, ImageFormatRg32i = 25, ImageFormatRg16i = 26, ImageFormatRg8i = 27, ImageFormatR16i = 28, ImageFormatR8i = 29, ImageFormatRgba32ui = 30, ImageFormatRgba16ui = 31, ImageFormatRgba8ui = 32, ImageFormatR32ui = 33, ImageFormatRgb10a2ui = 34, ImageFormatRg32ui = 35, ImageFormatRg16ui = 36, ImageFormatRg8ui = 37, ImageFormatR16ui = 38, ImageFormatR8ui = 39, }; enum ImageChannelOrder { ImageChannelOrderR = 0, ImageChannelOrderA = 1, ImageChannelOrderRG = 2, ImageChannelOrderRA = 3, ImageChannelOrderRGB = 4, ImageChannelOrderRGBA = 5, ImageChannelOrderBGRA = 6, ImageChannelOrderARGB = 7, ImageChannelOrderIntensity = 8, ImageChannelOrderLuminance = 9, ImageChannelOrderRx = 10, ImageChannelOrderRGx = 11, ImageChannelOrderRGBx = 12, ImageChannelOrderDepth = 13, ImageChannelOrderDepthStencil = 14, ImageChannelOrdersRGB = 15, ImageChannelOrdersRGBx = 16, ImageChannelOrdersRGBA = 17, ImageChannelOrdersBGRA = 18, }; enum ImageChannelDataType { ImageChannelDataTypeSnormInt8 = 0, ImageChannelDataTypeSnormInt16 = 1, ImageChannelDataTypeUnormInt8 = 2, ImageChannelDataTypeUnormInt16 = 3, ImageChannelDataTypeUnormShort565 = 4, ImageChannelDataTypeUnormShort555 = 5, ImageChannelDataTypeUnormInt101010 = 6, ImageChannelDataTypeSignedInt8 = 7, ImageChannelDataTypeSignedInt16 = 8, ImageChannelDataTypeSignedInt32 = 9, ImageChannelDataTypeUnsignedInt8 = 10, ImageChannelDataTypeUnsignedInt16 = 11, ImageChannelDataTypeUnsignedInt32 = 12, ImageChannelDataTypeHalfFloat = 13, ImageChannelDataTypeFloat = 14, ImageChannelDataTypeUnormInt24 = 15, ImageChannelDataTypeUnormInt101010_2 = 16, }; enum ImageOperandsShift { ImageOperandsBiasShift = 0, ImageOperandsLodShift = 1, ImageOperandsGradShift = 2, ImageOperandsConstOffsetShift = 3, ImageOperandsOffsetShift = 4, ImageOperandsConstOffsetsShift = 5, ImageOperandsSampleShift = 6, ImageOperandsMinLodShift = 7, }; enum ImageOperandsMask { ImageOperandsMaskNone = 0, ImageOperandsBiasMask = 0x00000001, ImageOperandsLodMask = 0x00000002, ImageOperandsGradMask = 0x00000004, ImageOperandsConstOffsetMask = 0x00000008, ImageOperandsOffsetMask = 0x00000010, ImageOperandsConstOffsetsMask = 0x00000020, ImageOperandsSampleMask = 0x00000040, ImageOperandsMinLodMask = 0x00000080, }; enum FPFastMathModeShift { FPFastMathModeNotNaNShift = 0, FPFastMathModeNotInfShift = 1, FPFastMathModeNSZShift = 2, FPFastMathModeAllowRecipShift = 3, FPFastMathModeFastShift = 4, }; enum FPFastMathModeMask { FPFastMathModeMaskNone = 0, FPFastMathModeNotNaNMask = 0x00000001, FPFastMathModeNotInfMask = 0x00000002, FPFastMathModeNSZMask = 0x00000004, FPFastMathModeAllowRecipMask = 0x00000008, FPFastMathModeFastMask = 0x00000010, }; enum FPRoundingMode { FPRoundingModeRTE = 0, FPRoundingModeRTZ = 1, FPRoundingModeRTP = 2, FPRoundingModeRTN = 3, FPRoundingModeCount /* internal use only */ }; enum LinkageType { LinkageTypeExport = 0, LinkageTypeImport = 1, LinkageTypeInternal, /* internal use only */ LinkageTypeCount /* internal use only */ }; enum AccessQualifier { AccessQualifierReadOnly = 0, AccessQualifierWriteOnly = 1, AccessQualifierReadWrite = 2, }; enum FunctionParameterAttribute { FunctionParameterAttributeZext = 0, FunctionParameterAttributeSext = 1, FunctionParameterAttributeByVal = 2, FunctionParameterAttributeSret = 3, FunctionParameterAttributeNoAlias = 4, FunctionParameterAttributeNoCapture = 5, FunctionParameterAttributeNoWrite = 6, FunctionParameterAttributeNoReadWrite = 7, FunctionParameterAttributeCount /* internal use only */ }; enum Decoration { DecorationRelaxedPrecision = 0, DecorationSpecId = 1, DecorationBlock = 2, DecorationBufferBlock = 3, DecorationRowMajor = 4, DecorationColMajor = 5, DecorationArrayStride = 6, DecorationMatrixStride = 7, DecorationGLSLShared = 8, DecorationGLSLPacked = 9, DecorationCPacked = 10, DecorationBuiltIn = 11, DecorationSmooth = 12, DecorationNoPerspective = 13, DecorationFlat = 14, DecorationPatch = 15, DecorationCentroid = 16, DecorationSample = 17, DecorationInvariant = 18, DecorationRestrict = 19, DecorationAliased = 20, DecorationVolatile = 21, DecorationConstant = 22, DecorationCoherent = 23, DecorationNonWritable = 24, DecorationNonReadable = 25, DecorationUniform = 26, DecorationSaturatedConversion = 28, DecorationStream = 29, DecorationLocation = 30, DecorationComponent = 31, DecorationIndex = 32, DecorationBinding = 33, DecorationDescriptorSet = 34, DecorationOffset = 35, DecorationXfbBuffer = 36, DecorationXfbStride = 37, DecorationFuncParamAttr = 38, DecorationFPRoundingMode = 39, DecorationFPFastMathMode = 40, DecorationLinkageAttributes = 41, DecorationNoContraction = 42, DecorationInputTargetIndex = 43, DecorationAlignment = 44, DecorationMaxByteOffset = 45, DecorationNoSignedWrap = 4469, DecorationNoUnsignedWrap = 4470, DecorationReferencedIndirectlyINTEL = 5602, DecorationSideEffectsINTEL = 5608, DecorationUserSemantic = 5635, }; enum BuiltIn { #define _SPIRV_OP(x, num) x = num, #include "SPIRVBuiltinEnum.h" #undef _SPIRV_OP BuiltInCount /* internal use only */ }; enum SelectionControlShift { SelectionControlFlattenShift = 0, SelectionControlDontFlattenShift = 1, }; enum SelectionControlMask { SelectionControlMaskNone = 0, SelectionControlFlattenMask = 0x00000001, SelectionControlDontFlattenMask = 0x00000002, }; enum LoopControlShift { LoopControlUnrollShift = 0, LoopControlDontUnrollShift = 1, LoopControlDependencyInfiniteShift = 2, LoopControlDependencyLengthShift = 3, LoopControlMax = 0x7fffffff, }; enum LoopControlMask { LoopControlMaskNone = 0, LoopControlUnrollMask = 0x00000001, LoopControlDontUnrollMask = 0x00000002, LoopControlDependencyInfiniteMask = 0x00000004, LoopControlDependencyLengthMask = 0x00000008, LoopControlMinIterationsMask = 0x00000010, LoopControlMaxIterationsMask = 0x00000020, LoopControlIterationMultipleMask = 0x00000040, LoopControlPeelCountMask = 0x00000080, LoopControlPartialCountMask = 0x00000100, LoopControlExtendedControlsMask = 0x80000000, }; enum FunctionControlShift { FunctionControlInlineShift = 0, FunctionControlDontInlineShift = 1, FunctionControlPureShift = 2, FunctionControlConstShift = 3, }; enum FunctionControlMask { FunctionControlMaskNone = 0, FunctionControlInlineMask = 0x00000001, FunctionControlDontInlineMask = 0x00000002, FunctionControlPureMask = 0x00000004, FunctionControlConstMask = 0x00000008, FunctionControlMaskMax = 0xF /* internal use only */ }; enum MemorySemanticsShift { MemorySemanticsAcquireShift = 1, MemorySemanticsReleaseShift = 2, MemorySemanticsAcquireReleaseShift = 3, MemorySemanticsSequentiallyConsistentShift = 4, MemorySemanticsUniformMemoryShift = 6, MemorySemanticsSubgroupMemoryShift = 7, MemorySemanticsWorkgroupLocalMemoryShift = 8, MemorySemanticsWorkgroupGlobalMemoryShift = 9, MemorySemanticsAtomicCounterMemoryShift = 10, MemorySemanticsImageMemoryShift = 11, }; enum MemorySemanticsMask { MemorySemanticsMaskNone = 0, MemorySemanticsAcquireMask = 0x00000002, MemorySemanticsReleaseMask = 0x00000004, MemorySemanticsAcquireReleaseMask = 0x00000008, MemorySemanticsSequentiallyConsistentMask = 0x00000010, MemorySemanticsUniformMemoryMask = 0x00000040, MemorySemanticsSubgroupMemoryMask = 0x00000080, MemorySemanticsWorkgroupLocalMemoryMask = 0x00000100, MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000200, MemorySemanticsAtomicCounterMemoryMask = 0x00000400, MemorySemanticsImageMemoryMask = 0x00000800, }; enum MemoryAccessShift { MemoryAccessVolatileShift = 0, MemoryAccessAlignedShift = 1, MemoryAccessNontemporalShift = 2, }; enum MemoryAccessMask { MemoryAccessMaskNone = 0, MemoryAccessVolatileMask = 0x00000001, MemoryAccessAlignedMask = 0x00000002, MemoryAccessNontemporalMask = 0x00000004, }; enum Scope { ScopeCrossDevice = 0, ScopeDevice = 1, ScopeWorkgroup = 2, ScopeSubgroup = 3, ScopeInvocation = 4, }; enum GroupOperation { GroupOperationReduce = 0, GroupOperationInclusiveScan = 1, GroupOperationExclusiveScan = 2, GroupOperationClusteredReduce = 3, GroupOperationCount /* internal use only */ }; enum KernelEnqueueFlags { KernelEnqueueFlagsNoWait = 0, KernelEnqueueFlagsWaitKernel = 1, KernelEnqueueFlagsWaitWorkGroup = 2, }; enum KernelProfilingInfoShift { KernelProfilingInfoCmdExecTimeShift = 0, }; enum KernelProfilingInfoMask { KernelProfilingInfoMaskNone = 0, KernelProfilingInfoCmdExecTimeMask = 0x00000001, }; enum Capability { CapabilityMatrix = 0, CapabilityShader = 1, CapabilityGeometry = 2, CapabilityTessellation = 3, CapabilityAddresses = 4, CapabilityLinkage = 5, CapabilityKernel = 6, CapabilityVector16 = 7, CapabilityFloat16Buffer = 8, CapabilityFloat16 = 9, CapabilityFloat64 = 10, CapabilityInt64 = 11, CapabilityInt64Atomics = 12, CapabilityImageBasic = 13, CapabilityImageReadWrite = 14, CapabilityImageMipmap = 15, CapabilityImageSRGBWrite = 16, CapabilityPipes = 17, CapabilityGroups = 18, CapabilityDeviceEnqueue = 19, CapabilityLiteralSampler = 20, CapabilityAtomicStorage = 21, CapabilityInt16 = 22, CapabilityTessellationPointSize = 23, CapabilityGeometryPointSize = 24, CapabilityImageGatherExtended = 25, CapabilityStorageImageExtendedFormats = 26, CapabilityStorageImageMultisample = 27, CapabilityUniformBufferArrayDynamicIndexing = 28, CapabilitySampledImageArrayDynamicIndexing = 29, CapabilityStorageBufferArrayDynamicIndexing = 30, CapabilityStorageImageArrayDynamicIndexing = 31, CapabilityClipDistance = 32, CapabilityCullDistance = 33, CapabilityImageCubeArray = 34, CapabilitySampleRateShading = 35, CapabilityImageRect = 36, CapabilitySampledRect = 37, CapabilityGenericPointer = 38, CapabilityInt8 = 39, CapabilityInputTarget = 40, CapabilitySparseResidency = 41, CapabilityMinLod = 42, CapabilitySampled1D = 43, CapabilityImage1D = 44, CapabilitySampledCubeArray = 45, CapabilitySampledBuffer = 46, CapabilityImageBuffer = 47, CapabilityImageMSArray = 48, CapabilityAdvancedFormats = 49, CapabilityImageQuery = 50, CapabilityDerivativeControl = 51, CapabilityInterpolationFunction = 52, CapabilityTransformFeedback = 53, CapabilityNamedBarrier = 54, CapabilitySubgroupDispatch = 58, CapabilityPipeStorage = 60, CapabilityNonUniform = 61, CapabilityNonUniformVote = 62, CapabilityNonUniformArithmetic = 63, CapabilityNonUniformBallot = 64, CapabilityNonUniformShuffle = 65, CapabilityNonUniformShuffleRelative = 66, CapabilityNonUniformClustered = 67, CapabilityNone = 1024, /* internal use only */ CapabilitySubgroupBallotKHR = 4423, CapabilitySubgroupShuffleINTEL = 5568, CapabilitySubgroupBufferBlockIOINTEL = 5569, CapabilitySubgroupImageBlockIOINTEL = 5570, CapabilitySubgroupImageMediaBlockIOINTEL = 5579, CapabilityFunctionPointersINTEL = 5603, CapabilityIndirectReferencesINTEL = 5604, CapabilityAsmINTEL = 5606, CapabilitySubgroupAvcMotionEstimationINTEL = 5696, CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, }; enum Op { #define _SPIRV_OP(x, num) Op##x = num, #include "SPIRVOpCodeEnum.h" #undef _SPIRV_OP }; // Overload operator| for mask bit combining inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); } inline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); } inline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); } inline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); } inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); } inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); } inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); } inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); } } // end namespace spv #endif // #ifndef spirv_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/TranslationBlock.h000066400000000000000000000225011363533017100252110ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #include #if defined(_WIN32) // INSIDE_PLUGIN must be defined in the pre-processor definitions of the // CTranslationBlock DLL project #define TRANSLATION_BLOCK_CALLING_CONV __cdecl #ifndef TRANSLATION_BLOCK_API #ifdef INSIDE_PLUGIN #define TRANSLATION_BLOCK_API __declspec(dllexport) #else #define TRANSLATION_BLOCK_API __declspec(dllimport) #endif #endif #else #define TRANSLATION_BLOCK_CALLING_CONV #ifndef TRANSLATION_BLOCK_API #define TRANSLATION_BLOCK_API __attribute__((visibility("default"))) #endif #endif namespace TC { static const uint32_t STB_VERSION = 1006UL; static const uint32_t STB_MAX_ERROR_STRING_SIZE = 1024UL; // Forward prototyping struct STB_RegisterArgs; struct STB_CreateArgs; class CTranslationBlock; extern "C" TRANSLATION_BLOCK_API void TRANSLATION_BLOCK_CALLING_CONV Register(STB_RegisterArgs* pRegisterArgs); extern "C" TRANSLATION_BLOCK_API CTranslationBlock* TRANSLATION_BLOCK_CALLING_CONV Create(STB_CreateArgs* pCreateArgs); extern "C" TRANSLATION_BLOCK_API void TRANSLATION_BLOCK_CALLING_CONV Delete(CTranslationBlock* pBlock); typedef void (TRANSLATION_BLOCK_CALLING_CONV *PFNREGISTER)(STB_RegisterArgs* pRegisterArgs); typedef CTranslationBlock* (TRANSLATION_BLOCK_CALLING_CONV *PFNCREATE)(STB_CreateArgs* pCreateArgs); typedef void (TRANSLATION_BLOCK_CALLING_CONV *PFNDELETE)(CTranslationBlock* pBlock); #undef TRANSLATION_BLOCK_CALLING_CONV /******************************************************************************\ Enumeration: TB_DATA_FORMAT Description: Possible i/o formats for the translation classes \******************************************************************************/ enum TB_DATA_FORMAT { TB_DATA_FORMAT_UNKNOWN, TB_DATA_FORMAT_OCL_TEXT, TB_DATA_FORMAT_OCL_BINARY, TB_DATA_FORMAT_LLVM_TEXT, TB_DATA_FORMAT_LLVM_BINARY, TB_DATA_FORMAT_GHAL_TEXT, TB_DATA_FORMAT_GHAL_BINARY, TB_DATA_FORMAT_DEVICE_TEXT, TB_DATA_FORMAT_DEVICE_BINARY, TB_DATA_FORMAT_LLVM_ARCHIVE, TB_DATA_FORMAT_ELF, TB_DATA_FORMAT_RS_LLVM_BINARY, TB_DATA_FORMAT_RS_INFO, TB_DATA_FORMAT_SPIR_V, TB_DATA_FORMAT_COHERENT_DEVICE_BINARY, TB_DATA_FORMAT_NON_COHERENT_DEVICE_BINARY, NUM_TB_DATA_FORMATS }; /******************************************************************************\ Structure: STB_TranslationCode Description: Structure used to describe the requested translation type \******************************************************************************/ union STB_TranslationCode { struct { TB_DATA_FORMAT Input : 16; TB_DATA_FORMAT Output : 16; }Type; uint32_t Code; }; /******************************************************************************\ Structure: STB_CreateArgs Description: Structure used to store arguments used to pass data to the Create function \******************************************************************************/ struct STB_CreateArgs { //INFO keep two first fields in this order ! for version ICBE 1003 compatibility STB_TranslationCode TranslationCode; void* pCreateData; STB_CreateArgs() { TranslationCode.Code = 0; pCreateData = NULL; } }; /******************************************************************************\ Structure: STB_RegisterArgs Description: Structure containing a pointer to an array of supported translation codes and a variable informing us of the size of the translation code array. The calling function is responsible for deleting the memory allocated for the translation code array. Note: Version is contained in this header \******************************************************************************/ struct STB_RegisterArgs { uint32_t Version; uint32_t NumTranslationCodes; STB_TranslationCode* pTranslationCodes; STB_RegisterArgs() { Version = STB_VERSION; NumTranslationCodes = 0; pTranslationCodes = NULL; } }; /******************************************************************************\ Structure: STB_TranslateInputArgs Description: Structure used to pass input variables to the translation block \******************************************************************************/ struct STB_TranslateInputArgs { char* pInput; // data to be translated uint32_t InputSize; // size of data to be translated const char* pOptions; // list of build/compile options uint32_t OptionsSize; // size of options list const char* pInternalOptions; // list of build/compile options uint32_t InternalOptionsSize; // size of options list void* pTracingOptions; // instrumentation options uint32_t TracingOptionsCount; // number of instrumentation options void* GTPinInput; // input structure for GTPin requests bool CompileTimeStatisticsEnable; const uint32_t* pSpecConstantsIds; // user-defined spec constants ids const uint64_t* pSpecConstantsValues; // spec constants values to be translated uint32_t SpecConstantsSize; // number of specialization constants STB_TranslateInputArgs() { pInput = NULL; InputSize = 0; pOptions = NULL; OptionsSize = 0; pInternalOptions = NULL; InternalOptionsSize = 0; pTracingOptions = NULL; TracingOptionsCount = 0; GTPinInput = NULL; CompileTimeStatisticsEnable = false; pSpecConstantsIds = NULL; pSpecConstantsValues = NULL; SpecConstantsSize = 0; } }; /******************************************************************************\ Structure: STB_TranslateOutputArgs Description: Structure used to hold data returned from the translation block \******************************************************************************/ struct STB_TranslateOutputArgs { char* pOutput; // pointer to translated data buffer uint32_t OutputSize; // translated data buffer size (bytes) char* pErrorString; // string to print if translate fails uint32_t ErrorStringSize; // size of error string char* pDebugData; // pointer to translated debug data buffer uint32_t DebugDataSize; // translated debug data data size (bytes) STB_TranslateOutputArgs() { pOutput = NULL; OutputSize = 0; pErrorString = NULL; ErrorStringSize = 0; pDebugData = NULL; DebugDataSize = 0; } }; struct TranslationBlockVersion { static const uint32_t VersioningIsUnsupported = (uint32_t)-1; uint32_t TBVersion; // STB_VERSION version of this translation block uint32_t BuildId; // build ID (for CI builds) of this translation block }; /******************************************************************************\ Class: CTranslationBlock Description: Interface used to expose required functions to translation plug-ins \******************************************************************************/ class CTranslationBlock { public: virtual bool Translate( const STB_TranslateInputArgs* pInput, STB_TranslateOutputArgs* pOutput ) = 0; virtual bool FreeAllocations( STB_TranslateOutputArgs* pOutput ) = 0; virtual bool GetOpcodes( void* pOpcodes, uint32_t pOpcodesSize ) { return false; } virtual bool GetOpcodesCount( uint32_t* pOpcodesCount, uint32_t* pOpcodeSize ){ return false; } virtual TranslationBlockVersion GetVersion() const { TranslationBlockVersion tbv; tbv.TBVersion = TC::STB_VERSION; uint32_t buildId = TranslationBlockVersion::VersioningIsUnsupported; #ifdef TB_BUILD_ID buildId = TB_BUILD_ID; #endif tbv.BuildId = buildId; return tbv; } virtual ~CTranslationBlock() {} }; } // namespace TC intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/UnifyIROCL.cpp000066400000000000000000000500121363533017100241540ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "common/LLVMWarningsPush.hpp" #include #include "llvm/ADT/PostOrderIterator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common/LLVMWarningsPop.hpp" #include "AdaptorCommon/AddImplicitArgs.hpp" #include "AdaptorCommon/ProcessFuncAttributes.h" #include "common/LLVMUtils.h" #include "Compiler/CISACodeGen/ShaderCodeGen.hpp" #include "Compiler/CISACodeGen/EstimateFunctionSize.h" #include "Compiler/CISACodeGen/FixAddrSpaceCast.h" #include "Compiler/CISACodeGen/ResolveGAS.h" #include "Compiler/CISACodeGen/ResolvePredefinedConstant.h" #include "Compiler/CISACodeGen/SimplifyConstant.h" #include "Compiler/CISACodeGen/FoldKnownWorkGroupSizes.h" #include "Compiler/HandleFRemInstructions.hpp" #include "Compiler/Optimizer/BuiltInFuncImport.h" #include "Compiler/Optimizer/CodeAssumption.hpp" #include "Compiler/Optimizer/Scalarizer.h" #include "Compiler/Optimizer/OpenCLPasses/DebuggerSupport/ImplicitGIDPass.hpp" #include "Compiler/Optimizer/OpenCLPasses/ExtenstionFuncs/ExtensionArgAnalysis.hpp" #include "Compiler/Optimizer/OpenCLPasses/ExtenstionFuncs/ExtensionFuncsAnalysis.hpp" #include "Compiler/Optimizer/OpenCLPasses/ExtenstionFuncs/ExtensionFuncResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/ImageFuncs/ImageFuncsAnalysis.hpp" #include "Compiler/Optimizer/OpenCLPasses/ImageFuncs/ImageFuncResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/PrivateMemory/PrivateMemoryUsageAnalysis.hpp" #include "Compiler/Optimizer/OpenCLPasses/PrivateMemory/PrivateMemoryResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/ProgramScopeConstants/ProgramScopeConstantAnalysis.hpp" #include "Compiler/Optimizer/OpenCLPasses/ProgramScopeConstants/ProgramScopeConstantResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/WIFuncs/WIFuncsAnalysis.hpp" #include "Compiler/Optimizer/OpenCLPasses/WIFuncs/WIFuncResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/ResourceAllocator/ResourceAllocator.hpp" #include "Compiler/Optimizer/OpenCLPasses/BreakConstantExpr/BreakConstantExpr.hpp" #include "Compiler/Optimizer/OpenCLPasses/LocalBuffers/InlineLocalsResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/ReplaceUnsupportedIntrinsics/ReplaceUnsupportedIntrinsics.hpp" #include "Compiler/Optimizer/OpenCLPasses/Atomics/ResolveOCLAtomics.hpp" #include "Compiler/Optimizer/OpenCLPasses/WGFuncs/WGFuncResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/AlignmentAnalysis/AlignmentAnalysis.hpp" #include "Compiler/Optimizer/PreCompiledFuncImport.hpp" #include "Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/OpenCLPrintfAnalysis.hpp" #include "Compiler/Optimizer/OpenCLPasses/OpenCLPrintf/OpenCLPrintfResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/AggregateArguments/AggregateArguments.hpp" #include "Compiler/Optimizer/OpenCLPasses/UnreachableHandling/UnreachableHandling.hpp" #include "Compiler/Optimizer/OCLBIConverter.h" #include "Compiler/Optimizer/OpenCLPasses/SetFastMathFlags/SetFastMathFlags.hpp" #include "Compiler/Optimizer/OpenCLPasses/CorrectlyRoundedDivSqrt/CorrectlyRoundedDivSqrt.hpp" #include "Compiler/Optimizer/OpenCLPasses/GenericAddressResolution/GenericAddressDynamicResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/AddressSpaceAliasAnalysis/AddressSpaceAliasAnalysis.h" #include "Compiler/Optimizer/OpenCLPasses/DeviceEnqueueFuncs/DeviceEnqueue.hpp" #include "Compiler/Optimizer/OpenCLPasses/DeviceEnqueueFuncs/TransformBlocks.hpp" #include "Compiler/Optimizer/OpenCLPasses/UndefinedReferences/UndefinedReferencesPass.hpp" #include "Compiler/Optimizer/OpenCLPasses/SubGroupFuncs/SubGroupFuncsResolution.hpp" #include "Compiler/Optimizer/OpenCLPasses/BIFTransforms/BIFTransforms.hpp" #include "Compiler/Optimizer/OpenCLPasses/BreakdownIntrinsic.h" #include "Compiler/Optimizer/OpenCLPasses/StatelessToStatefull/StatelessToStatefull.hpp" #include "Compiler/Optimizer/OpenCLPasses/KernelFunctionCloning.h" #include "Compiler/Legalizer/TypeLegalizerPass.h" #include "Compiler/Optimizer/OpenCLPasses/ClampLoopUnroll/ClampLoopUnroll.hpp" #include "Compiler/Optimizer/OpenCLPasses/Image3dToImage2darray/Image3dToImage2darray.hpp" #include "Compiler/Optimizer/OpenCLPasses/RewriteLocalSize/RewriteLocalSize.hpp" #include "Compiler/MetaDataApi/PurgeMetaDataUtils.hpp" #include "Compiler/MetaDataUtilsWrapper.h" #include "Compiler/SPIRMetaDataTranslation.h" #include "Compiler/Optimizer/OpenCLPasses/ErrorCheckPass.h" #include "Compiler/MetaDataApi/IGCMetaDataHelper.h" #include "Compiler/CodeGenContextWrapper.hpp" #include "Compiler/FixResourcePtr.hpp" #include "Compiler/InitializePasses.h" #include "Compiler/MetaDataApi/SpirMetaDataApi.h" #include "Compiler/Optimizer/FixFastMathFlags.hpp" #include "MoveStaticAllocas.h" #include "Compiler/Optimizer/IGCInstCombiner/IGCInstructionCombining.hpp" #include "common/debug/Debug.hpp" #include "common/igc_regkeys.hpp" #include "common/debug/Dump.hpp" #include "common/MemStats.h" #include #include "Compiler/DebugInfo/VISADebugEmitter.hpp" #include "Compiler/CISACodeGen/DebugInfo.hpp" #include "Compiler/CISACodeGen/TimeStatsCounter.h" #include #include using namespace llvm; using namespace IGC::IGCMD; using namespace IGC::Debug; namespace IGC { int getOCLMajorVersion(const SPIRMD::SpirMetaDataUtils &spirMDUtils) { int oclMajor = 0, oclMinor = 0; if (spirMDUtils.isOpenCLVersionsHasValue()) { SPIRMD::VersionMetaDataHandle oclVersion = spirMDUtils.getOpenCLVersionsItem(0); oclMajor = oclVersion->getMajor(); oclMinor = oclVersion->getMinor(); } else { if (!spirMDUtils.empty_CompilerOptions()) { // check compiler options for (auto i = spirMDUtils.getCompilerOptionsItem(0)->begin(), e = spirMDUtils.getCompilerOptionsItem(0)->end(); i != e; ++i) { if (StringRef(*i).startswith("-cl-std=CL") && i->length() >= 13) { oclMajor = i->at(10) - '0'; oclMinor = i->at(12) - '0'; break; } } } // default is 1.2 if (!isLegalOCLVersion(oclMajor, oclMinor)) { oclMajor = 1; oclMinor = 2; } } return oclMajor; } static void CommonOCLBasedPasses( OpenCLProgramContext* pContext, std::unique_ptr BuiltinGenericModule, std::unique_ptr BuiltinSizeModule) { IGCPassManager mpm(pContext, "Unify"); #if defined( _DEBUG ) llvm::verifyModule(*pContext->getModule()); #endif COMPILER_TIME_START(pContext, TIME_UnificationPasses); unify_opt_PreProcess(pContext); DumpLLVMIR(pContext, "beforeUnification"); // override the data layout to match Gen HW int pointerSize = getPointerSize(*pContext->getModule()); std::string layoutstr; if (pointerSize == 4) { layoutstr = "e-p:32:32:32"; } else { layoutstr = "e-p:64:64:64"; } layoutstr += "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64"\ "-f32:32:32-f64:64:64-v16:16:16-v24:32:32"\ "-v32:32:32-v48:64:64-v64:64:64-v96:128:128"\ "-v128:128:128-v192:256:256-v256:256:256"\ "-v512:512:512-v1024:1024:1024-n8:16:32"; StringRef dataLayout = layoutstr; pContext->getModule()->setDataLayout(dataLayout); BuiltinGenericModule->setDataLayout(dataLayout); if( BuiltinSizeModule ) { BuiltinSizeModule->setDataLayout(dataLayout); } MetaDataUtils *pMdUtils = pContext->getMetaDataUtils(); //extracting OCL version major before SPIRMetadataTranslation pass deletes its metadata node const SPIRMD::SpirMetaDataUtils spirMDUtils(&(*pContext->getModule())); int OCLMajor = getOCLMajorVersion(spirMDUtils); CompOptions &CompilerOpts = pContext->getModuleMetaData()->compOpt; // check OpenCL build options bool shouldForceCR = pContext->m_Options.CorrectlyRoundedSqrt; CompilerOpts.replaceGlobalOffsetsByZero = pContext->m_InternalOptions.replaceGlobalOffsetsByZero; CompilerOpts.SubgroupIndependentForwardProgressRequired = (pContext->m_Options.NoSubgroupIFP == false); if (OCLMajor >= 2) { CompilerOpts.UniformWGS = pContext->m_Options.UniformWGS; } CompilerOpts.GreaterThan2GBBufferRequired = !pContext->m_InternalOptions.Use32BitPtrArith; CompilerOpts.GreaterThan4GBBufferRequired = pContext->m_InternalOptions.IntelGreaterThan4GBBufferRequired; CompilerOpts.DisableA64WA = pContext->m_InternalOptions.IntelDisableA64WA; CompilerOpts.HasBufferOffsetArg = pContext->m_InternalOptions.IntelHasBufferOffsetArg; CompilerOpts.PreferBindlessImages = pContext->m_InternalOptions.PreferBindlessImages; if (CompilerOpts.PreferBindlessImages) { pContext->getModuleMetaData()->UseBindlessImage = true; } CompilerOpts.EnableTakeGlobalAddress = pContext->m_Options.EnableTakeGlobalAddress; // right now we don't support any standard function in the code gen // maybe we want to support some at some point to take advantage of LLVM optimizations TargetLibraryInfoImpl TLI; TLI.disableAllFunctions(); mpm.add( new llvm::TargetLibraryInfoWrapperPass(TLI)); // This should be removed, once FE will be updated to use LLVM IR that supports // AllowContract and ApproxFunc FastMathFlags. mpm.add(new FixFastMathFlags()); IGCPassManager mpmSPIR(pContext, "Unify"); mpmSPIR.add(new MetaDataUtilsWrapper(pMdUtils, pContext->getModuleMetaData())); mpmSPIR.add(new CodeGenContextWrapper(pContext)); mpmSPIR.add(new SPIRMetaDataTranslation()); mpmSPIR.run(*pContext->getModule()); mpm.add(new MetaDataUtilsWrapper(pMdUtils, pContext->getModuleMetaData())); mpm.add(new CodeGenContextWrapper(pContext)); mpm.add(new ClampLoopUnroll(256)); mpm.add(new MoveStaticAllocas()); mpm.add(new UnreachableHandling()); // Skip this pass if OCL version < 2.0 if (!(OCLMajor < 2)) { mpm.add(createTransformBlocksPass()); } // Clone kernel function being used as user function. mpm.add(createKernelFunctionCloningPass()); mpm.add(new CorrectlyRoundedDivSqrt(shouldForceCR, false)); if(IGC_IS_FLAG_ENABLED(EnableIntelFast)) { mpm.add(createBIFTransformsPass()); } if(pContext->m_InternalOptions.KernelDebugEnable) { IF_DEBUG_INFO(mpm.add(new ImplicitGlobalId());) } if (IGC_IS_FLAG_ENABLED(EnableCodeAssumption)) { mpm.add(new CodeAssumption()); } if (pContext->m_instrTypes.hasFRem) { mpm.add(new HandleFRemInstructions()); } mpm.add(new PreBIImportAnalysis()); mpm.add(createTimeStatsCounterPass(pContext, TIME_Unify_BuiltinImport, STATS_COUNTER_START)); mpm.add(createBuiltInImportPass(std::move(BuiltinGenericModule), std::move(BuiltinSizeModule))); mpm.add(createTimeStatsCounterPass(pContext, TIME_Unify_BuiltinImport, STATS_COUNTER_END)); mpm.add(new UndefinedReferencesPass()); // Estimate maximal function size in the module and disable subroutine if not profitable. mpm.add(createEstimateFunctionSizePass()); if (IGC_GET_FLAG_VALUE(AllowMem2Reg)) { mpm.add(createPromoteMemoryToRegisterPass()); } mpm.add(new CatchAllLineNumber()); // OCL has built-ins so it always need to run inlining { mpm.add(createProcessFuncAttributesPass()); if (IGC_GET_FLAG_VALUE(FunctionControl) != FLAG_FCALL_FORCE_INLINE) { int Threshold = IGC_GET_FLAG_VALUE(OCLInlineThreshold); mpm.add(createFunctionInliningPass(Threshold)); } else { mpm.add(createAlwaysInlinerLegacyPass()); } // The inliner sometimes fails to delete unused functions, this cleans up the remaining mess. mpm.add(createGlobalDCEPass()); // Check after GlobalDCE in case of doubles in dead functions mpm.add(new ErrorCheck()); if (IGC_GET_FLAG_VALUE(FunctionControl) != FLAG_FCALL_FORCE_INLINE) { mpm.add(createProcessBuiltinMetaDataPass()); } mpm.add(new PurgeMetaDataUtils()); } // OpenCL WI + image function resolution // OCLTODO : do another DCE that will get rid of unused WI func calls before this? // We can save passing of unused implicit args from the runtime // Adding Mem2Reg pass in order to help ImageFuncsAnalysis to identify the image arguments // that the image functions operate on // Clang output is: alloca --> store image func arg into allocated address --> // load image arg from stored address --> call func on loaded image // After Mem2Reg: call func on image func arg mpm.add(createSROAPass()); mpm.add(new BreakConstantExpr()); if (IGC_IS_FLAG_ENABLED(EnableGASResolver)) { // Add fix up of illegal `addrspacecast` in respect to OCL 2.0 spec. mpm.add(createFixAddrSpaceCastPass()); mpm.add(createResolveGASPass()); // Run another round of constant breaking as GAS resolving may generate constants (constant address) mpm.add(new BreakConstantExpr()); } if (CompilerOpts.UniformWGS) mpm.add(new RewriteLocalSize()); mpm.add(createSROAPass()); mpm.add(new BreakConstantExpr()); mpm.add(CreateFoldKnownWorkGroupSizes()); // 64-bit atomics have to be resolved before AddImplicitArgs pass as it uses // local ids for spin lock initialization mpm.add(new ResolveOCLAtomics()); // Run the AlignmentAnalysis pass before the passes which add implicit arguments, to ensure we do not lose load/store alignment information. // For example, ProgramScopeConstantResolution will relocate the buffer's base to an i8* typed pointer. mpm.add(new AlignmentAnalysis()); // Analysis passes mpm.add(new WIFuncsAnalysis()); mpm.add(new ImageFuncsAnalysis()); mpm.add(new OpenCLPrintfAnalysis()); mpm.add(createDeadCodeEliminationPass()); mpm.add(new ProgramScopeConstantAnalysis()); mpm.add(new PrivateMemoryUsageAnalysis()); mpm.add(new AggregateArgumentsAnalysis()); mpm.add(new ExtensionFuncsAnalysis()); mpm.add(new ExtensionArgAnalysis()); mpm.add(new DeviceEnqueueFuncsAnalysis()); mpm.add(createGenericAddressAnalysisPass()); if (IGC_GET_FLAG_VALUE(FunctionControl) != FLAG_FCALL_FORCE_INLINE) { mpm.add(new BuiltinCallGraphAnalysis()); } // Adding implicit args based on Analysis passes mpm.add(new AddImplicitArgs()); // Resolution passes mpm.add(new WIFuncResolution()); mpm.add(new OpenCLPrintfResolution()); mpm.add(new ResolveOCLAtomics()); mpm.add(new ResourceAllocator()); mpm.add(new SubGroupFuncsResolution()); // Run InlineLocals and GenericAddressDynamic together mpm.add(new InlineLocalsResolution()); mpm.add(new WGFuncResolution()); mpm.add(new ResolveAggregateArguments()); mpm.add(new ExtensionFuncsResolution()); mpm.add(new DeviceEnqueueFuncsResolution()); mpm.add(createDeadCodeEliminationPass()); mpm.add(createBuiltinsConverterPass()); mpm.add(new ImageFuncResolution()); mpm.add(new Image3dToImage2darray()); // Break down the intrinsics into smaller operations (eg. fmuladd to fmul add) mpm.add(new BreakdownIntrinsicPass()); { if(IGC_IS_FLAG_ENABLED(EnableConstantPromotion)) { mpm.add(createSimplifyConstantPass()); mpm.add(createPromoteConstantPass()); } mpm.add(createIGCInstructionCombiningPass()); // Instcombine can create constant expressions, which are not handled by the program scope constant resolution pass mpm.add(new BreakConstantExpr()); // Run constant lowering conservatively for tests where constant // objects are over-written after casting pointers in constant address // space into ones in private address. // // NOTE: Per OpenCL C standard (both 1.2 and 2.0), that's illegal. // // This has to be run after instcombine to allow memcpy from GlobalVariable arrays private // allocs to be optimized away. mpm.add(new ProgramScopeConstantResolution(true)); } // TODO: Run CheckInstrTypes after builtin import to determine if builtins have allocas. mpm.add(createSROAPass()); mpm.add(createIGCInstructionCombiningPass()); // "false" to createScalarizerPass() means that vector load/stores are NOT scalarized mpm.add(createScalarizerPass(false)); // Add SetFastMathFalgs pass at the end so that we don't need to worry about previous passes that // forget setting math flags. We expect the generic llvm optimizations after the unification // (optimizeIR()) will fully take advantage of the flags. mpm.add(new SetFastMathFlags()); mpm.add(new FixResourcePtr()); bool isOptDisabled = CompilerOpts.OptDisable; if(isOptDisabled) { // Run additional predefined constant resolving when optimization is // disabled. It's definitely a workaround so far. mpm.add(createResolvePredefinedConstantPass()); } mpm.add(createLowerSwitchPass()); mpm.add(createTypeLegalizerPass()); mpm.run(*pContext->getModule()); // Following functions checks whether -g option is specified. // The flag is set only in SPIRMetadataTranslationPass which // is run in above mpm.run statement. The downside of calling // this function here, as opposed to beginning of this function, // is that unreferenced constants will be eliminated. So // debugger will not be able to query those variables. IF_DEBUG_INFO(insertOCLMissingDebugConstMetadata(pContext);) COMPILER_TIME_END(pContext, TIME_UnificationPasses); DumpLLVMIR(pContext, "afterUnification"); MEM_SNAPSHOT(IGC::SMS_AFTER_UNIFICATION); } void UnifyIROCL( OpenCLProgramContext* pContext, std::unique_ptr BuiltinGenericModule, std::unique_ptr BuiltinSizeModule) { CommonOCLBasedPasses(pContext, std::move(BuiltinGenericModule), std::move(BuiltinSizeModule)); } void UnifyIRSPIR( OpenCLProgramContext* pContext, std::unique_ptr BuiltinGenericModule, std::unique_ptr BuiltinSizeModule) { CommonOCLBasedPasses(pContext, std::move(BuiltinGenericModule), std::move(BuiltinSizeModule)); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/UnifyIROCL.hpp000066400000000000000000000031671363533017100241720ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "Compiler/CodeGenPublic.h" namespace IGC { void UnifyIROCL( OpenCLProgramContext* pContext, std::unique_ptr BuiltinGenericModule, std::unique_ptr BuiltinSizeModule); void UnifyIRSPIR( OpenCLProgramContext* pContext, std::unique_ptr BuiltinGenericModule, std::unique_ptr BuiltinSizeModule); }intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/000077500000000000000000000000001363533017100233405ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/Upgrader.h000066400000000000000000000027661363533017100252750ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #if LLVM_VERSION_MAJOR == 4 #include "llvm4/Upgrader.h" #elif LLVM_VERSION_MAJOR == 7 #include "llvm7/Upgrader.h" #elif LLVM_VERSION_MAJOR == 8 #include "llvm8/Upgrader.h" #elif LLVM_VERSION_MAJOR == 9 #include "llvm9/Upgrader.h" #elif LLVM_VERSION_MAJOR == 10 #include "llvm10/Upgrader.h" #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm10/000077500000000000000000000000001363533017100244535ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm10/BitcodeReader.cpp000066400000000000000000007474121363533017100276720ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "MetadataLoader.h" #include "ValueList.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalIndirectSymbol.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "common/LLVMWarningsPop.hpp" #include "BitcodeReader.h" #include "Probe.h" using namespace llvm; //===----------------------------------------------------------------------===// // upgrade bitcast to addrspacecast when necessary //===----------------------------------------------------------------------===// Instruction *upgradeBitCastInst(unsigned Opc, Value *V, Type *DestTy, Instruction *&Temp) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = V->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return CastInst::Create(Instruction::AddrSpaceCast, V, DestTy); } return nullptr; } Value *upgradeBitCastExpr(unsigned Opc, Constant *C, Type *DestTy) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = C->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return ConstantExpr::getAddrSpaceCast(C, DestTy); } return nullptr; } namespace { enum { SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; } // end anonymous namespace static Error error(const Twine &Message) { return make_error( Message, make_error_code(BitcodeError::CorruptedBitcode)); } static Error hasInvalidBitcodeHeader(BitstreamCursor &Stream) { if (!Stream.canSkipToPos(4)) return createStringError(std::errc::illegal_byte_sequence, "file too small to contain bitcode header"); for (unsigned C : {'B', 'C'}) if (Expected Res = Stream.Read(8)) { if (Res.get() != C) return createStringError(std::errc::illegal_byte_sequence, "file doesn't start with bitcode header"); } else return Res.takeError(); for (unsigned C : {0x0, 0xC, 0xE, 0xD}) if (Expected Res = Stream.Read(4)) { if (Res.get() != C) return createStringError(std::errc::illegal_byte_sequence, "file doesn't start with bitcode header"); } else return Res.takeError(); return Error::success(); } static Expected initStream(MemoryBufferRef Buffer) { const unsigned char *BufPtr = (const unsigned char *)Buffer.getBufferStart(); const unsigned char *BufEnd = BufPtr + Buffer.getBufferSize(); if (Buffer.getBufferSize() & 3) return error("Invalid bitcode signature"); // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. if (isBitcodeWrapper(BufPtr, BufEnd)) if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) return error("Invalid bitcode wrapper header"); BitstreamCursor Stream(ArrayRef(BufPtr, BufEnd)); if (Error Err = hasInvalidBitcodeHeader(Stream)) return std::move(Err); return std::move(Stream); } /// Convert a string from a record into an std::string, return true on failure. template static bool convertToString(ArrayRef Record, unsigned Idx, StrTy &Result) { if (Idx > Record.size()) return true; for (unsigned i = Idx, e = Record.size(); i != e; ++i) Result += (char)Record[i]; return false; } // Strip all the TBAA attachment for the module. static void stripTBAA(Module *M) { for (auto &F : *M) { if (F.isMaterializable()) continue; for (auto &I : instructions(F)) I.setMetadata(LLVMContext::MD_tbaa, nullptr); } } /// Read the "IDENTIFICATION_BLOCK_ID" block, do some basic enforcement on the /// "epoch" encoded in the bitcode, and return the producer name if any. static Expected readIdentificationBlock(BitstreamCursor &Stream) { if (Error Err = Stream.EnterSubBlock(bitc::IDENTIFICATION_BLOCK_ID)) return std::move(Err); // Read all the records. SmallVector Record; std::string ProducerIdentification; while (true) { BitstreamEntry Entry; if (Expected Res = Stream.advance()) Entry = Res.get(); else return Res.takeError(); switch (Entry.Kind) { default: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ProducerIdentification; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (MaybeBitCode.get()) { default: // Default behavior: reject return error("Invalid value"); case bitc::IDENTIFICATION_CODE_STRING: // IDENTIFICATION: [strchr x N] convertToString(Record, 0, ProducerIdentification); break; case bitc::IDENTIFICATION_CODE_EPOCH: { // EPOCH: [epoch#] unsigned epoch = (unsigned)Record[0]; if (epoch != bitc::BITCODE_CURRENT_EPOCH) { return error( Twine("Incompatible epoch: Bitcode '") + Twine(epoch) + "' vs current: '" + Twine(bitc::BITCODE_CURRENT_EPOCH) + "'"); } } } } } static Expected readIdentificationCode(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { if (Stream.AtEndOfStream()) return ""; BitstreamEntry Entry; if (Expected Res = Stream.advance()) Entry = std::move(Res.get()); else return Res.takeError(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) return readIdentificationBlock(Stream); // Ignore other sub-blocks. if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; case BitstreamEntry::Record: if (Expected Skipped = Stream.skipRecord(Entry.ID)) continue; else return Skipped.takeError(); } } } static Expected hasObjCCategoryInModule(BitstreamCursor &Stream) { if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return std::move(Err); SmallVector Record; // Read all the records for this module. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Check for the i386 and other (x86_64, ARM) conventions if (S.find("__DATA,__objc_catlist") != std::string::npos || S.find("__OBJC,__category") != std::string::npos) return true; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } static Expected hasObjCCategory(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { BitstreamEntry Entry; if (Expected Res = Stream.advance()) Entry = std::move(Res.get()); else return Res.takeError(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return hasObjCCategoryInModule(Stream); // Ignore other sub-blocks. if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; case BitstreamEntry::Record: if (Expected Skipped = Stream.skipRecord(Entry.ID)) continue; else return Skipped.takeError(); } } } static Expected readModuleTriple(BitstreamCursor &Stream) { if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return std::move(Err); SmallVector Record; std::string Triple; // Read all the records for this module. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Triple; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); Triple = S; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } static Expected readTriple(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ""; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return readModuleTriple(Stream); // Ignore other sub-blocks. if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; case BitstreamEntry::Record: if (llvm::Expected Skipped = Stream.skipRecord(Entry.ID)) continue; else return Skipped.takeError(); } } } namespace { class BitcodeReaderBase { protected: BitcodeReaderBase(BitstreamCursor Stream, StringRef Strtab) : Stream(std::move(Stream)), Strtab(Strtab) { this->Stream.setBlockInfo(&BlockInfo); } BitstreamBlockInfo BlockInfo; BitstreamCursor Stream; StringRef Strtab; /// In version 2 of the bitcode we store names of global values and comdats in /// a string table rather than in the VST. bool UseStrtab = false; Expected parseVersionRecord(ArrayRef Record); /// If this module uses a string table, pop the reference to the string table /// and return the referenced string and the rest of the record. Otherwise /// just return the record itself. std::pair> readNameFromStrtab(ArrayRef Record); bool readBlockInfo(); // Contains an arbitrary and optional string identifying the bitcode producer std::string ProducerIdentification; Error error(const Twine &Message); }; } // end anonymous namespace Error BitcodeReaderBase::error(const Twine &Message) { std::string FullMsg = Message.str(); if (!ProducerIdentification.empty()) FullMsg += " (Producer: '" + ProducerIdentification + "' Reader: 'LLVM " + LLVM_VERSION_STRING "')"; return ::error(FullMsg); } Expected BitcodeReaderBase::parseVersionRecord(ArrayRef Record) { if (Record.empty()) return error("Invalid record"); unsigned ModuleVersion = Record[0]; if (ModuleVersion > 2) return error("Invalid value"); UseStrtab = ModuleVersion >= 2; return ModuleVersion; } std::pair> BitcodeReaderBase::readNameFromStrtab(ArrayRef Record) { if (!UseStrtab) return {"", Record}; // Invalid reference. Let the caller complain about the record being empty. if (Record[0] + Record[1] > Strtab.size()) return {"", {}}; return {StringRef(Strtab.data() + Record[0], Record[1]), Record.slice(2)}; } namespace { class BitcodeReader : public BitcodeReaderBase, public GVMaterializer { LLVMContext &Context; Module *TheModule = nullptr; // Next offset to start scanning for lazy parsing of function bodies. uint64_t NextUnreadBit = 0; // Last function offset found in the VST. uint64_t LastFunctionBlockBit = 0; bool SeenValueSymbolTable = false; uint64_t VSTOffset = 0; std::vector SectionTable; std::vector GCTable; std::vector TypeList; DenseMap FunctionTypes; BitcodeReaderValueList ValueList; Optional MDLoader; std::vector ComdatList; SmallVector InstructionList; std::vector> GlobalInits; std::vector> IndirectSymbolInits; std::vector> FunctionPrefixes; std::vector> FunctionPrologues; std::vector> FunctionPersonalityFns; /// The set of attributes by index. Index zero in the file is for null, and /// is thus not represented here. As such all indices are off by one. std::vector MAttributes; /// The set of attribute groups. std::map MAttributeGroups; /// While parsing a function body, this is a list of the basic blocks for the /// function. std::vector FunctionBBs; // When reading the module header, this list is populated with functions that // have bodies later in the file. std::vector FunctionsWithBodies; // When intrinsic functions are encountered which require upgrading they are // stored here with their replacement function. using UpdatedIntrinsicMap = DenseMap; UpdatedIntrinsicMap UpgradedIntrinsics; // Intrinsics which were remangled because of types rename UpdatedIntrinsicMap RemangledIntrinsics; // Several operations happen after the module header has been read, but // before function bodies are processed. This keeps track of whether // we've done this yet. bool SeenFirstFunctionBody = false; /// When function bodies are initially scanned, this map contains info about /// where to find deferred function body in the stream. DenseMap DeferredFunctionInfo; /// When Metadata block is initially scanned when parsing the module, we may /// choose to defer parsing of the metadata. This vector contains info about /// which Metadata blocks are deferred. std::vector DeferredMetadataInfo; /// These are basic blocks forward-referenced by block addresses. They are /// inserted lazily into functions when they're loaded. The basic block ID is /// its index into the vector. DenseMap> BasicBlockFwdRefs; std::deque BasicBlockFwdRefQueue; /// Indicates that we are using a new encoding for instruction operands where /// most operands in the current FUNCTION_BLOCK are encoded relative to the /// instruction number, for a more compact encoding. Some instruction /// operands are not relative to the instruction ID: basic block numbers, and /// types. Once the old style function blocks have been phased out, we would /// not need this flag. bool UseRelativeIDs = false; /// True if all functions will be materialized, negating the need to process /// (e.g.) blockaddress forward references. bool WillMaterializeAllForwardRefs = false; bool StripDebugInfo = false; TBAAVerifier TBAAVerifyHelper; std::vector BundleTags; SmallVector SSIDs; public: BitcodeReader(BitstreamCursor Stream, StringRef Strtab, StringRef ProducerIdentification, LLVMContext &Context); Error materializeForwardReferencedFunctions(); Error materialize(GlobalValue *GV) override; Error materializeModule() override; std::vector getIdentifiedStructTypes() const override; /// Main interface to parsing a bitcode buffer. /// \returns true if an error occurred. Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); static uint64_t decodeSignRotatedValue(uint64_t V); /// Materialize any deferred Metadata block. Error materializeMetadata() override; void setStripDebugInfo() override; private: std::vector IdentifiedStructTypes; StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); StructType *createIdentifiedStructType(LLVMContext &Context); /// Map all pointer types within \param Ty to the opaque pointer /// type in the same address space if opaque pointers are being /// used, otherwise nop. This converts a bitcode-reader internal /// type into one suitable for use in a Value. Type *flattenPointerTypes(Type *Ty) { return Ty; } /// Given a fully structured pointer type (i.e. not opaque), return /// the flattened form of its element, suitable for use in a Value. Type *getPointerElementFlatType(Type *Ty) { return flattenPointerTypes(cast(Ty)->getElementType()); } /// Given a fully structured pointer type, get its element type in /// both fully structured form, and flattened form suitable for use /// in a Value. std::pair getPointerElementTypes(Type *FullTy) { Type *ElTy = cast(FullTy)->getElementType(); return std::make_pair(ElTy, flattenPointerTypes(ElTy)); } /// Return the flattened type (suitable for use in a Value) /// specified by the given \param ID . Type *getTypeByID(unsigned ID) { return flattenPointerTypes(getFullyStructuredTypeByID(ID)); } /// Return the fully structured (bitcode-reader internal) type /// corresponding to the given \param ID . Type *getFullyStructuredTypeByID(unsigned ID); Value *getFnValueByID(unsigned ID, Type *Ty, Type **FullTy = nullptr) { if (Ty && Ty->isMetadataTy()) return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); return ValueList.getValueFwdRef(ID, Ty, FullTy); } Metadata *getFnMetadataByID(unsigned ID) { return MDLoader->getMetadataFwdRefOrLoad(ID); } BasicBlock *getBasicBlock(unsigned ID) const { if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID return FunctionBBs[ID]; } AttributeList getAttributes(unsigned i) const { if (i-1 < MAttributes.size()) return MAttributes[i-1]; return AttributeList(); } /// Read a value/type pair out of the specified record from slot 'Slot'. /// Increment Slot past the number of slots used in the record. Return true on /// failure. bool getValueTypePair(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Value *&ResVal, Type **FullTy = nullptr) { if (Slot == Record.size()) return true; unsigned ValNo = (unsigned)Record[Slot++]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; if (ValNo < InstNum) { // If this is not a forward reference, just return the value we already // have. ResVal = getFnValueByID(ValNo, nullptr, FullTy); return ResVal == nullptr; } if (Slot == Record.size()) return true; unsigned TypeNo = (unsigned)Record[Slot++]; ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo)); if (FullTy) *FullTy = getFullyStructuredTypeByID(TypeNo); return ResVal == nullptr; } /// Read a value out of the specified record from slot 'Slot'. Increment Slot /// past the number of slots used by the value in the record. Return true if /// there is an error. bool popValue(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { if (getValue(Record, Slot, InstNum, Ty, ResVal)) return true; // All values currently take a single record slot. ++Slot; return false; } /// Like popValue, but does not increment the Slot number. bool getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { ResVal = getValue(Record, Slot, InstNum, Ty); return ResVal == nullptr; } /// Version of getValue that returns ResVal directly, or 0 if there is an /// error. Value *getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)Record[Slot]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Like getValue, but decodes signed VBRs. Value *getValueSigned(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)decodeSignRotatedValue(Record[Slot]); // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Upgrades old-style typeless byval attributes by adding the corresponding /// argument's pointee type. void propagateByValTypes(CallBase *CB, ArrayRef ArgsFullTys); /// Converts alignment exponent (i.e. power of two (or zero)) to the /// corresponding alignment to use. If alignment is too large, returns /// a corresponding error code. Error parseAlignmentValue(uint64_t Exponent, MaybeAlign &Alignment); Error parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind); Error parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata = false); Error parseComdatRecord(ArrayRef Record); Error parseGlobalVarRecord(ArrayRef Record); Error parseFunctionRecord(ArrayRef Record); Error parseGlobalIndirectSymbolRecord(unsigned BitCode, ArrayRef Record); Error parseAttributeBlock(); Error parseAttributeGroupBlock(); Error parseTypeTable(); Error parseTypeTableBody(); Error parseOperandBundleTags(); Error parseSyncScopeNames(); Expected recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT); void setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F, ArrayRef Record); Error parseValueSymbolTable(uint64_t Offset = 0); Error parseGlobalValueSymbolTable(); Error parseConstants(); Error rememberAndSkipFunctionBodies(); Error rememberAndSkipFunctionBody(); /// Save the positions of the Metadata blocks and skip parsing the blocks. Error rememberAndSkipMetadata(); Error typeCheckLoadStoreInst(Type *ValType, Type *PtrType); Error parseFunctionBody(Function *F); Error globalCleanup(); Error resolveGlobalAndIndirectSymbolInits(); Error parseUseLists(); Error findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator); SyncScope::ID getDecodedSyncScopeID(unsigned Val); }; /// Class to manage reading and parsing function summary index bitcode /// files/sections. class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase { /// The module index built during parsing. ModuleSummaryIndex &TheIndex; /// Indicates whether we have encountered a global value summary section /// yet during parsing. bool SeenGlobalValSummary = false; /// Indicates whether we have already parsed the VST, used for error checking. bool SeenValueSymbolTable = false; /// Set to the offset of the VST recorded in the MODULE_CODE_VSTOFFSET record. /// Used to enable on-demand parsing of the VST. uint64_t VSTOffset = 0; // Map to save ValueId to ValueInfo association that was recorded in the // ValueSymbolTable. It is used after the VST is parsed to convert // call graph edges read from the function summary from referencing // callees by their ValueId to using the ValueInfo instead, which is how // they are recorded in the summary index being built. // We save a GUID which refers to the same global as the ValueInfo, but // ignoring the linkage, i.e. for values other than local linkage they are // identical. DenseMap> ValueIdToValueInfoMap; /// Map populated during module path string table parsing, from the /// module ID to a string reference owned by the index's module /// path string table, used to correlate with combined index /// summary records. DenseMap ModuleIdMap; /// Original source file name recorded in a bitcode record. std::string SourceFileName; /// The string identifier given to this module by the client, normally the /// path to the bitcode file. StringRef ModulePath; /// For per-module summary indexes, the unique numerical identifier given to /// this module by the client. unsigned ModuleId; public: ModuleSummaryIndexBitcodeReader(BitstreamCursor Stream, StringRef Strtab, ModuleSummaryIndex &TheIndex, StringRef ModulePath, unsigned ModuleId); Error parseModule(); private: void setValueGUID(uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage, StringRef SourceFileName); Error parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap); std::vector makeRefList(ArrayRef Record); std::vector makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile, bool HasRelBF); Error parseEntireSummary(unsigned ID); Error parseModuleStringTable(); void parseTypeIdCompatibleVtableSummaryRecord(ArrayRef Record); void parseTypeIdCompatibleVtableInfo(ArrayRef Record, size_t &Slot, TypeIdCompatibleVtableInfo &TypeId); std::pair getValueInfoFromValueId(unsigned ValueId); void addThisModule(); ModuleSummaryIndex::ModuleInfo *getThisModule(); }; } // end anonymous namespace BitcodeReader::BitcodeReader(BitstreamCursor Stream, StringRef Strtab, StringRef ProducerIdentification, LLVMContext &Context) : BitcodeReaderBase(std::move(Stream), Strtab), Context(Context), ValueList(Context, Stream.SizeInBytes()) { this->ProducerIdentification = ProducerIdentification; } Error BitcodeReader::materializeForwardReferencedFunctions() { if (WillMaterializeAllForwardRefs) return Error::success(); // Prevent recursion. WillMaterializeAllForwardRefs = true; while (!BasicBlockFwdRefQueue.empty()) { Function *F = BasicBlockFwdRefQueue.front(); BasicBlockFwdRefQueue.pop_front(); IGC_ASSERT(F && "Expected valid function"); if (!BasicBlockFwdRefs.count(F)) // Already materialized. continue; // Check for a function that isn't materializable to prevent an infinite // loop. When parsing a blockaddress stored in a global variable, there // isn't a trivial way to check if a function will have a body without a // linear search through FunctionsWithBodies, so just check it here. if (!F->isMaterializable()) return error("Never resolved function from blockaddress"); // Try to materialize F. if (Error Err = materialize(F)) return Err; } IGC_ASSERT(BasicBlockFwdRefs.empty() && "Function missing from queue"); // Reset state. WillMaterializeAllForwardRefs = false; return Error::success(); } //===----------------------------------------------------------------------===// // Helper functions to implement forward reference resolution, etc. //===----------------------------------------------------------------------===// static bool hasImplicitComdat(size_t Val) { switch (Val) { default: return false; case 1: // Old WeakAnyLinkage case 4: // Old LinkOnceAnyLinkage case 10: // Old WeakODRLinkage case 11: // Old LinkOnceODRLinkage return true; } } static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) { switch (Val) { default: // Map unknown/new linkages to external case 0: return GlobalValue::ExternalLinkage; case 2: return GlobalValue::AppendingLinkage; case 3: return GlobalValue::InternalLinkage; case 5: return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage case 6: return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage case 7: return GlobalValue::ExternalWeakLinkage; case 8: return GlobalValue::CommonLinkage; case 9: return GlobalValue::PrivateLinkage; case 12: return GlobalValue::AvailableExternallyLinkage; case 13: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage case 14: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateWeakLinkage case 15: return GlobalValue::ExternalLinkage; // Obsolete LinkOnceODRAutoHideLinkage case 1: // Old value with implicit comdat. case 16: return GlobalValue::WeakAnyLinkage; case 10: // Old value with implicit comdat. case 17: return GlobalValue::WeakODRLinkage; case 4: // Old value with implicit comdat. case 18: return GlobalValue::LinkOnceAnyLinkage; case 11: // Old value with implicit comdat. case 19: return GlobalValue::LinkOnceODRLinkage; } } static FunctionSummary::FFlags getDecodedFFlags(uint64_t RawFlags) { FunctionSummary::FFlags Flags; Flags.ReadNone = RawFlags & 0x1; Flags.ReadOnly = (RawFlags >> 1) & 0x1; Flags.NoRecurse = (RawFlags >> 2) & 0x1; Flags.ReturnDoesNotAlias = (RawFlags >> 3) & 0x1; Flags.NoInline = (RawFlags >> 4) & 0x1; Flags.AlwaysInline = (RawFlags >> 5) & 0x1; return Flags; } /// Decode the flags for GlobalValue in the summary. static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags, uint64_t Version) { // Summary were not emitted before LLVM 3.9, we don't need to upgrade Linkage // like getDecodedLinkage() above. Any future change to the linkage enum and // to getDecodedLinkage() will need to be taken into account here as above. auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits RawFlags = RawFlags >> 4; bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3; // The Live flag wasn't introduced until version 3. For dead stripping // to work correctly on earlier versions, we must conservatively treat all // values as live. bool Live = (RawFlags & 0x2) || Version < 3; bool Local = (RawFlags & 0x4); bool AutoHide = (RawFlags & 0x8); return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live, Local, AutoHide); } // Decode the flags for GlobalVariable in the summary static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) { return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false, (RawFlags & 0x2) ? true : false); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { switch (Val) { default: // Map unknown visibilities to default. case 0: return GlobalValue::DefaultVisibility; case 1: return GlobalValue::HiddenVisibility; case 2: return GlobalValue::ProtectedVisibility; } } static GlobalValue::DLLStorageClassTypes getDecodedDLLStorageClass(unsigned Val) { switch (Val) { default: // Map unknown values to default. case 0: return GlobalValue::DefaultStorageClass; case 1: return GlobalValue::DLLImportStorageClass; case 2: return GlobalValue::DLLExportStorageClass; } } static bool getDecodedDSOLocal(unsigned Val) { switch(Val) { default: // Map unknown values to preemptable. case 0: return false; case 1: return true; } } static GlobalVariable::ThreadLocalMode getDecodedThreadLocalMode(unsigned Val) { switch (Val) { case 0: return GlobalVariable::NotThreadLocal; default: // Map unknown non-zero value to general dynamic. case 1: return GlobalVariable::GeneralDynamicTLSModel; case 2: return GlobalVariable::LocalDynamicTLSModel; case 3: return GlobalVariable::InitialExecTLSModel; case 4: return GlobalVariable::LocalExecTLSModel; } } static GlobalVariable::UnnamedAddr getDecodedUnnamedAddrType(unsigned Val) { switch (Val) { default: // Map unknown to UnnamedAddr::None. case 0: return GlobalVariable::UnnamedAddr::None; case 1: return GlobalVariable::UnnamedAddr::Global; case 2: return GlobalVariable::UnnamedAddr::Local; } } static int getDecodedCastOpcode(unsigned Val) { switch (Val) { default: return -1; case bitc::CAST_TRUNC : return Instruction::Trunc; case bitc::CAST_ZEXT : return Instruction::ZExt; case bitc::CAST_SEXT : return Instruction::SExt; case bitc::CAST_FPTOUI : return Instruction::FPToUI; case bitc::CAST_FPTOSI : return Instruction::FPToSI; case bitc::CAST_UITOFP : return Instruction::UIToFP; case bitc::CAST_SITOFP : return Instruction::SIToFP; case bitc::CAST_FPTRUNC : return Instruction::FPTrunc; case bitc::CAST_FPEXT : return Instruction::FPExt; case bitc::CAST_PTRTOINT: return Instruction::PtrToInt; case bitc::CAST_INTTOPTR: return Instruction::IntToPtr; case bitc::CAST_BITCAST : return Instruction::BitCast; case bitc::CAST_ADDRSPACECAST: return Instruction::AddrSpaceCast; } } static int getDecodedUnaryOpcode(unsigned Val, Type *Ty) { bool IsFP = Ty->isFPOrFPVectorTy(); // UnOps are only valid for int/fp or vector of int/fp types if (!IsFP && !Ty->isIntOrIntVectorTy()) return -1; switch (Val) { default: return -1; case bitc::UNOP_FNEG: return IsFP ? Instruction::FNeg : -1; } } static int getDecodedBinaryOpcode(unsigned Val, Type *Ty) { bool IsFP = Ty->isFPOrFPVectorTy(); // BinOps are only valid for int/fp or vector of int/fp types if (!IsFP && !Ty->isIntOrIntVectorTy()) return -1; switch (Val) { default: return -1; case bitc::BINOP_ADD: return IsFP ? Instruction::FAdd : Instruction::Add; case bitc::BINOP_SUB: return IsFP ? Instruction::FSub : Instruction::Sub; case bitc::BINOP_MUL: return IsFP ? Instruction::FMul : Instruction::Mul; case bitc::BINOP_UDIV: return IsFP ? -1 : Instruction::UDiv; case bitc::BINOP_SDIV: return IsFP ? Instruction::FDiv : Instruction::SDiv; case bitc::BINOP_UREM: return IsFP ? -1 : Instruction::URem; case bitc::BINOP_SREM: return IsFP ? Instruction::FRem : Instruction::SRem; case bitc::BINOP_SHL: return IsFP ? -1 : Instruction::Shl; case bitc::BINOP_LSHR: return IsFP ? -1 : Instruction::LShr; case bitc::BINOP_ASHR: return IsFP ? -1 : Instruction::AShr; case bitc::BINOP_AND: return IsFP ? -1 : Instruction::And; case bitc::BINOP_OR: return IsFP ? -1 : Instruction::Or; case bitc::BINOP_XOR: return IsFP ? -1 : Instruction::Xor; } } static AtomicRMWInst::BinOp getDecodedRMWOperation(unsigned Val) { switch (Val) { default: return AtomicRMWInst::BAD_BINOP; case bitc::RMW_XCHG: return AtomicRMWInst::Xchg; case bitc::RMW_ADD: return AtomicRMWInst::Add; case bitc::RMW_SUB: return AtomicRMWInst::Sub; case bitc::RMW_AND: return AtomicRMWInst::And; case bitc::RMW_NAND: return AtomicRMWInst::Nand; case bitc::RMW_OR: return AtomicRMWInst::Or; case bitc::RMW_XOR: return AtomicRMWInst::Xor; case bitc::RMW_MAX: return AtomicRMWInst::Max; case bitc::RMW_MIN: return AtomicRMWInst::Min; case bitc::RMW_UMAX: return AtomicRMWInst::UMax; case bitc::RMW_UMIN: return AtomicRMWInst::UMin; case bitc::RMW_FADD: return AtomicRMWInst::FAdd; case bitc::RMW_FSUB: return AtomicRMWInst::FSub; } } static AtomicOrdering getDecodedOrdering(unsigned Val) { switch (Val) { case bitc::ORDERING_NOTATOMIC: return AtomicOrdering::NotAtomic; case bitc::ORDERING_UNORDERED: return AtomicOrdering::Unordered; case bitc::ORDERING_MONOTONIC: return AtomicOrdering::Monotonic; case bitc::ORDERING_ACQUIRE: return AtomicOrdering::Acquire; case bitc::ORDERING_RELEASE: return AtomicOrdering::Release; case bitc::ORDERING_ACQREL: return AtomicOrdering::AcquireRelease; default: // Map unknown orderings to sequentially-consistent. case bitc::ORDERING_SEQCST: return AtomicOrdering::SequentiallyConsistent; } } static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) { switch (Val) { default: // Map unknown selection kinds to any. case bitc::COMDAT_SELECTION_KIND_ANY: return Comdat::Any; case bitc::COMDAT_SELECTION_KIND_EXACT_MATCH: return Comdat::ExactMatch; case bitc::COMDAT_SELECTION_KIND_LARGEST: return Comdat::Largest; case bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES: return Comdat::NoDuplicates; case bitc::COMDAT_SELECTION_KIND_SAME_SIZE: return Comdat::SameSize; } } static FastMathFlags getDecodedFastMathFlags(unsigned Val) { FastMathFlags FMF; if (0 != (Val & bitc::UnsafeAlgebra)) FMF.setFast(); if (0 != (Val & bitc::AllowReassoc)) FMF.setAllowReassoc(); if (0 != (Val & bitc::NoNaNs)) FMF.setNoNaNs(); if (0 != (Val & bitc::NoInfs)) FMF.setNoInfs(); if (0 != (Val & bitc::NoSignedZeros)) FMF.setNoSignedZeros(); if (0 != (Val & bitc::AllowReciprocal)) FMF.setAllowReciprocal(); if (0 != (Val & bitc::AllowContract)) FMF.setAllowContract(true); if (0 != (Val & bitc::ApproxFunc)) FMF.setApproxFunc(); return FMF; } static void upgradeDLLImportExportLinkage(GlobalValue *GV, unsigned Val) { switch (Val) { case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break; case 6: GV->setDLLStorageClass(GlobalValue::DLLExportStorageClass); break; } } Type *BitcodeReader::getFullyStructuredTypeByID(unsigned ID) { // The type table size is always specified correctly. if (ID >= TypeList.size()) return nullptr; if (Type *Ty = TypeList[ID]) return Ty; // If we have a forward reference, the only possible case is when it is to a // named struct. Just create a placeholder for now. return TypeList[ID] = createIdentifiedStructType(Context); } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context, StringRef Name) { auto *Ret = StructType::create(Context, Name); IdentifiedStructTypes.push_back(Ret); return Ret; } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) { auto *Ret = StructType::create(Context); IdentifiedStructTypes.push_back(Ret); return Ret; } //===----------------------------------------------------------------------===// // Functions for parsing blocks from the bitcode file //===----------------------------------------------------------------------===// static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { switch (Val) { case Attribute::EndAttrKinds: llvm_unreachable("Synthetic enumerators which should never get here"); case Attribute::None: return 0; case Attribute::ZExt: return 1 << 0; case Attribute::SExt: return 1 << 1; case Attribute::NoReturn: return 1 << 2; case Attribute::InReg: return 1 << 3; case Attribute::StructRet: return 1 << 4; case Attribute::NoUnwind: return 1 << 5; case Attribute::NoAlias: return 1 << 6; case Attribute::ByVal: return 1 << 7; case Attribute::Nest: return 1 << 8; case Attribute::ReadNone: return 1 << 9; case Attribute::ReadOnly: return 1 << 10; case Attribute::NoInline: return 1 << 11; case Attribute::AlwaysInline: return 1 << 12; case Attribute::OptimizeForSize: return 1 << 13; case Attribute::StackProtect: return 1 << 14; case Attribute::StackProtectReq: return 1 << 15; case Attribute::Alignment: return 31 << 16; case Attribute::NoCapture: return 1 << 21; case Attribute::NoRedZone: return 1 << 22; case Attribute::NoImplicitFloat: return 1 << 23; case Attribute::Naked: return 1 << 24; case Attribute::InlineHint: return 1 << 25; case Attribute::StackAlignment: return 7 << 26; case Attribute::ReturnsTwice: return 1 << 29; case Attribute::UWTable: return 1 << 30; case Attribute::NonLazyBind: return 1U << 31; case Attribute::SanitizeAddress: return 1ULL << 32; case Attribute::MinSize: return 1ULL << 33; case Attribute::NoDuplicate: return 1ULL << 34; case Attribute::StackProtectStrong: return 1ULL << 35; case Attribute::SanitizeThread: return 1ULL << 36; case Attribute::SanitizeMemory: return 1ULL << 37; case Attribute::NoBuiltin: return 1ULL << 38; case Attribute::Returned: return 1ULL << 39; case Attribute::Cold: return 1ULL << 40; case Attribute::Builtin: return 1ULL << 41; case Attribute::OptimizeNone: return 1ULL << 42; case Attribute::InAlloca: return 1ULL << 43; case Attribute::NonNull: return 1ULL << 44; case Attribute::JumpTable: return 1ULL << 45; case Attribute::Convergent: return 1ULL << 46; case Attribute::SafeStack: return 1ULL << 47; case Attribute::NoRecurse: return 1ULL << 48; case Attribute::InaccessibleMemOnly: return 1ULL << 49; case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50; case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; case Attribute::WriteOnly: return 1ULL << 53; case Attribute::Speculatable: return 1ULL << 54; case Attribute::StrictFP: return 1ULL << 55; case Attribute::SanitizeHWAddress: return 1ULL << 56; case Attribute::NoCfCheck: return 1ULL << 57; case Attribute::OptForFuzzing: return 1ULL << 58; case Attribute::ShadowCallStack: return 1ULL << 59; case Attribute::SpeculativeLoadHardening: return 1ULL << 60; case Attribute::ImmArg: return 1ULL << 61; case Attribute::WillReturn: return 1ULL << 62; case Attribute::NoFree: return 1ULL << 63; case Attribute::NoSync: llvm_unreachable("nosync attribute not supported in raw format"); break; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; case Attribute::DereferenceableOrNull: llvm_unreachable("dereferenceable_or_null attribute not supported in raw " "format"); break; case Attribute::ArgMemOnly: llvm_unreachable("argmemonly attribute not supported in raw format"); break; case Attribute::AllocSize: llvm_unreachable("allocsize not supported in raw format"); break; case Attribute::SanitizeMemTag: llvm_unreachable("sanitize_memtag attribute not supported in raw format"); break; default: llvm_unreachable("Unsupported attribute type"); //return 0; } } static void addRawAttributeValue(AttrBuilder &B, uint64_t Val) { if (!Val) return; for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; I = Attribute::AttrKind(I + 1)) { if (I == Attribute::SanitizeMemTag || I == Attribute::Dereferenceable || I == Attribute::DereferenceableOrNull || I == Attribute::ArgMemOnly || I == Attribute::AllocSize || I == Attribute::NoSync) continue; if (uint64_t A = (Val & getRawAttributeMask(I))) { if (I == Attribute::Alignment) B.addAlignmentAttr(1ULL << ((A >> 16) - 1)); else if (I == Attribute::StackAlignment) B.addStackAlignmentAttr(1ULL << ((A >> 26)-1)); else B.addAttribute(I); } } } /// This fills an AttrBuilder object with the LLVM attributes that have /// been decoded from the given integer. This function must stay in sync with /// 'encodeLLVMAttributesForBitcode'. static void decodeLLVMAttributesForBitcode(AttrBuilder &B, uint64_t EncodedAttrs) { // FIXME: Remove in 4.0. // The alignment is stored as a 16-bit raw value from bits 31--16. We shift // the bits above 31 down by 11 bits. unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; IGC_ASSERT((!Alignment || isPowerOf2_32(Alignment)) && "Alignment must be a power of two."); if (Alignment) B.addAlignmentAttr(Alignment); addRawAttributeValue(B, ((EncodedAttrs & (0xfffffULL << 32)) >> 11) | (EncodedAttrs & 0xffff)); } Error BitcodeReader::parseAttributeBlock() { if (Error Err = Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID)) return Err; if (!MAttributes.empty()) return error("Invalid multiple blocks"); SmallVector Record; SmallVector Attrs; // Read all the records. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_CODE_ENTRY_OLD: // ENTRY: [paramidx0, attr0, ...] // FIXME: Remove in 4.0. if (Record.size() & 1) return error("Invalid record"); for (unsigned i = 0, e = Record.size(); i != e; i += 2) { AttrBuilder B; decodeLLVMAttributesForBitcode(B, Record[i+1]); Attrs.push_back(AttributeList::get(Context, Record[i], B)); } MAttributes.push_back(AttributeList::get(Context, Attrs)); Attrs.clear(); break; case bitc::PARAMATTR_CODE_ENTRY: // ENTRY: [attrgrp0, attrgrp1, ...] for (unsigned i = 0, e = Record.size(); i != e; ++i) Attrs.push_back(MAttributeGroups[Record[i]]); MAttributes.push_back(AttributeList::get(Context, Attrs)); Attrs.clear(); break; } } } // Returns Attribute::None on unrecognized codes. static Attribute::AttrKind getAttrFromCode(uint64_t Code) { switch (Code) { default: return Attribute::None; case bitc::ATTR_KIND_ALIGNMENT: return Attribute::Alignment; case bitc::ATTR_KIND_ALWAYS_INLINE: return Attribute::AlwaysInline; case bitc::ATTR_KIND_ARGMEMONLY: return Attribute::ArgMemOnly; case bitc::ATTR_KIND_BUILTIN: return Attribute::Builtin; case bitc::ATTR_KIND_BY_VAL: return Attribute::ByVal; case bitc::ATTR_KIND_IN_ALLOCA: return Attribute::InAlloca; case bitc::ATTR_KIND_COLD: return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: return Attribute::InaccessibleMemOnly; case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: return Attribute::InaccessibleMemOrArgMemOnly; case bitc::ATTR_KIND_INLINE_HINT: return Attribute::InlineHint; case bitc::ATTR_KIND_IN_REG: return Attribute::InReg; case bitc::ATTR_KIND_JUMP_TABLE: return Attribute::JumpTable; case bitc::ATTR_KIND_MIN_SIZE: return Attribute::MinSize; case bitc::ATTR_KIND_NAKED: return Attribute::Naked; case bitc::ATTR_KIND_NEST: return Attribute::Nest; case bitc::ATTR_KIND_NO_ALIAS: return Attribute::NoAlias; case bitc::ATTR_KIND_NO_BUILTIN: return Attribute::NoBuiltin; case bitc::ATTR_KIND_NO_CAPTURE: return Attribute::NoCapture; case bitc::ATTR_KIND_NO_DUPLICATE: return Attribute::NoDuplicate; case bitc::ATTR_KIND_NOFREE: return Attribute::NoFree; case bitc::ATTR_KIND_NO_IMPLICIT_FLOAT: return Attribute::NoImplicitFloat; case bitc::ATTR_KIND_NO_INLINE: return Attribute::NoInline; case bitc::ATTR_KIND_NO_RECURSE: return Attribute::NoRecurse; case bitc::ATTR_KIND_NON_LAZY_BIND: return Attribute::NonLazyBind; case bitc::ATTR_KIND_NON_NULL: return Attribute::NonNull; case bitc::ATTR_KIND_DEREFERENCEABLE: return Attribute::Dereferenceable; case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: return Attribute::DereferenceableOrNull; case bitc::ATTR_KIND_ALLOC_SIZE: return Attribute::AllocSize; case bitc::ATTR_KIND_NO_RED_ZONE: return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: return Attribute::NoReturn; case bitc::ATTR_KIND_NOSYNC: return Attribute::NoSync; case bitc::ATTR_KIND_NOCF_CHECK: return Attribute::NoCfCheck; case bitc::ATTR_KIND_NO_UNWIND: return Attribute::NoUnwind; case bitc::ATTR_KIND_OPT_FOR_FUZZING: return Attribute::OptForFuzzing; case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: return Attribute::OptimizeForSize; case bitc::ATTR_KIND_OPTIMIZE_NONE: return Attribute::OptimizeNone; case bitc::ATTR_KIND_READ_NONE: return Attribute::ReadNone; case bitc::ATTR_KIND_READ_ONLY: return Attribute::ReadOnly; case bitc::ATTR_KIND_RETURNED: return Attribute::Returned; case bitc::ATTR_KIND_RETURNS_TWICE: return Attribute::ReturnsTwice; case bitc::ATTR_KIND_S_EXT: return Attribute::SExt; case bitc::ATTR_KIND_SPECULATABLE: return Attribute::Speculatable; case bitc::ATTR_KIND_STACK_ALIGNMENT: return Attribute::StackAlignment; case bitc::ATTR_KIND_STACK_PROTECT: return Attribute::StackProtect; case bitc::ATTR_KIND_STACK_PROTECT_REQ: return Attribute::StackProtectReq; case bitc::ATTR_KIND_STACK_PROTECT_STRONG: return Attribute::StackProtectStrong; case bitc::ATTR_KIND_SAFESTACK: return Attribute::SafeStack; case bitc::ATTR_KIND_SHADOWCALLSTACK: return Attribute::ShadowCallStack; case bitc::ATTR_KIND_STRICT_FP: return Attribute::StrictFP; case bitc::ATTR_KIND_STRUCT_RET: return Attribute::StructRet; case bitc::ATTR_KIND_SANITIZE_ADDRESS: return Attribute::SanitizeAddress; case bitc::ATTR_KIND_SANITIZE_HWADDRESS: return Attribute::SanitizeHWAddress; case bitc::ATTR_KIND_SANITIZE_THREAD: return Attribute::SanitizeThread; case bitc::ATTR_KIND_SANITIZE_MEMORY: return Attribute::SanitizeMemory; case bitc::ATTR_KIND_SPECULATIVE_LOAD_HARDENING: return Attribute::SpeculativeLoadHardening; case bitc::ATTR_KIND_SWIFT_ERROR: return Attribute::SwiftError; case bitc::ATTR_KIND_SWIFT_SELF: return Attribute::SwiftSelf; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; case bitc::ATTR_KIND_WILLRETURN: return Attribute::WillReturn; case bitc::ATTR_KIND_WRITEONLY: return Attribute::WriteOnly; case bitc::ATTR_KIND_Z_EXT: return Attribute::ZExt; case bitc::ATTR_KIND_IMMARG: return Attribute::ImmArg; case bitc::ATTR_KIND_SANITIZE_MEMTAG: return Attribute::SanitizeMemTag; } } Error BitcodeReader::parseAlignmentValue(uint64_t Exponent, MaybeAlign &Alignment) { // Note: Alignment in bitcode files is incremented by 1, so that zero // can be used for default alignment. if (Exponent > Value::MaxAlignmentExponent + 1) return error("Invalid alignment value"); Alignment = decodeMaybeAlign(Exponent); return Error::success(); } Error BitcodeReader::parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind) { *Kind = getAttrFromCode(Code); if (*Kind == Attribute::None) return error("Unknown attribute kind (" + Twine(Code) + ")"); return Error::success(); } Error BitcodeReader::parseAttributeGroupBlock() { if (Error Err = Stream.EnterSubBlock(bitc::PARAMATTR_GROUP_BLOCK_ID)) return Err; if (!MAttributeGroups.empty()) return error("Invalid multiple blocks"); SmallVector Record; // Read all the records. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_GRP_CODE_ENTRY: { // ENTRY: [grpid, idx, a0, a1, ...] if (Record.size() < 3) return error("Invalid record"); uint64_t GrpID = Record[0]; uint64_t Idx = Record[1]; // Index of the object this attribute refers to. AttrBuilder B; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Record[i] == 0) { // Enum attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; // Upgrade old-style byval attribute to one with a type, even if it's // nullptr. We will have to insert the real type when we associate // this AttributeList with a function. if (Kind == Attribute::ByVal) B.addByValAttr(nullptr); B.addAttribute(Kind); } else if (Record[i] == 1) { // Integer attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; if (Kind == Attribute::Alignment) B.addAlignmentAttr(Record[++i]); else if (Kind == Attribute::StackAlignment) B.addStackAlignmentAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); else if (Kind == Attribute::DereferenceableOrNull) B.addDereferenceableOrNullAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); } else if (Record[i] == 3 || Record[i] == 4) { // String attribute bool HasValue = (Record[i++] == 4); SmallString<64> KindStr; SmallString<64> ValStr; while (Record[i] != 0 && i != e) KindStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Kind string not null terminated"); if (HasValue) { // Has a value associated with it. ++i; // Skip the '0' that terminates the "kind" string. while (Record[i] != 0 && i != e) ValStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Value string not null terminated"); } B.addAttribute(KindStr.str(), ValStr.str()); } else { IGC_ASSERT((Record[i] == 5 || Record[i] == 6) && "Invalid attribute group entry"); bool HasType = Record[i] == 6; Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; if (Kind == Attribute::ByVal) B.addByValAttr(HasType ? getTypeByID(Record[++i]) : nullptr); } } UpgradeFramePointerAttributes(B); MAttributeGroups[GrpID] = AttributeList::get(Context, Idx, B); break; } } } } Error BitcodeReader::parseTypeTable() { if (Error Err = Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW)) return Err; return parseTypeTableBody(); } Error BitcodeReader::parseTypeTableBody() { if (!TypeList.empty()) return error("Invalid multiple blocks"); SmallVector Record; unsigned NumRecords = 0; SmallString<64> TypeName; // Read all the records for this type table. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NumRecords != TypeList.size()) return error("Malformed block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *ResultTy = nullptr; Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: return error("Invalid value"); case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] // TYPE_CODE_NUMENTRY contains a count of the number of types in the // type list. This allows us to reserve space. if (Record.size() < 1) return error("Invalid record"); TypeList.resize(Record[0]); continue; case bitc::TYPE_CODE_VOID: // VOID ResultTy = Type::getVoidTy(Context); break; case bitc::TYPE_CODE_HALF: // HALF ResultTy = Type::getHalfTy(Context); break; case bitc::TYPE_CODE_FLOAT: // FLOAT ResultTy = Type::getFloatTy(Context); break; case bitc::TYPE_CODE_DOUBLE: // DOUBLE ResultTy = Type::getDoubleTy(Context); break; case bitc::TYPE_CODE_X86_FP80: // X86_FP80 ResultTy = Type::getX86_FP80Ty(Context); break; case bitc::TYPE_CODE_FP128: // FP128 ResultTy = Type::getFP128Ty(Context); break; case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 ResultTy = Type::getPPC_FP128Ty(Context); break; case bitc::TYPE_CODE_LABEL: // LABEL ResultTy = Type::getLabelTy(Context); break; case bitc::TYPE_CODE_METADATA: // METADATA ResultTy = Type::getMetadataTy(Context); break; case bitc::TYPE_CODE_X86_MMX: // X86_MMX ResultTy = Type::getX86_MMXTy(Context); break; case bitc::TYPE_CODE_TOKEN: // TOKEN ResultTy = Type::getTokenTy(Context); break; case bitc::TYPE_CODE_INTEGER: { // INTEGER: [width] if (Record.size() < 1) return error("Invalid record"); uint64_t NumBits = Record[0]; if (NumBits < IntegerType::MIN_INT_BITS || NumBits > IntegerType::MAX_INT_BITS) return error("Bitwidth for integer type out of range"); ResultTy = IntegerType::get(Context, NumBits); break; } case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or // [pointee type, address space] if (Record.size() < 1) return error("Invalid record"); unsigned AddressSpace = 0; if (Record.size() == 2) AddressSpace = Record[1]; ResultTy = getTypeByID(Record[0]); if (!ResultTy || !PointerType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = PointerType::get(ResultTy, AddressSpace); break; } case bitc::TYPE_CODE_FUNCTION_OLD: { // FIXME: attrid is dead, remove it in LLVM 4.0 // FUNCTION: [vararg, attrid, retty, paramty x N] if (Record.size() < 3) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 3, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) ArgTys.push_back(T); else break; } ResultTy = getTypeByID(Record[2]); if (!ResultTy || ArgTys.size() < Record.size()-3) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_FUNCTION: { // FUNCTION: [vararg, retty, paramty x N] if (Record.size() < 2) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) { if (!FunctionType::isValidArgumentType(T)) return error("Invalid function argument type"); ArgTys.push_back(T); } else break; } ResultTy = getTypeByID(Record[1]); if (!ResultTy || ArgTys.size() < Record.size()-2) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid type"); ResultTy = StructType::get(Context, EltTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N] if (convertToString(Record, 0, TypeName)) return error("Invalid record"); continue; case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid record"); Res->setBody(EltTys, Record[0]); ResultTy = Res; break; } case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: [] if (Record.size() != 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct with no body. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); ResultTy = Res; break; } case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !ArrayType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = ArrayType::get(ResultTy, Record[0]); break; case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] or // [numelts, eltty, scalable] if (Record.size() < 2) return error("Invalid record"); if (Record[0] == 0) return error("Invalid vector length"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !StructType::isValidElementType(ResultTy)) return error("Invalid type"); bool Scalable = Record.size() > 2 ? Record[2] : false; ResultTy = VectorType::get(ResultTy, Record[0], Scalable); break; } if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); if (TypeList[NumRecords]) return error( "Invalid TYPE table: Only named structs can be forward referenced"); IGC_ASSERT(ResultTy && "Didn't read a type?"); TypeList[NumRecords++] = ResultTy; } } Error BitcodeReader::parseOperandBundleTags() { if (Error Err = Stream.EnterSubBlock(bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID)) return Err; if (!BundleTags.empty()) return error("Invalid multiple blocks"); SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Tags are implicitly mapped to integers by their order. Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); if (MaybeRecord.get() != bitc::OPERAND_BUNDLE_TAG) return error("Invalid record"); // OPERAND_BUNDLE_TAG: [strchr x N] BundleTags.emplace_back(); if (convertToString(Record, 0, BundleTags.back())) return error("Invalid record"); Record.clear(); } } Error BitcodeReader::parseSyncScopeNames() { if (Error Err = Stream.EnterSubBlock(bitc::SYNC_SCOPE_NAMES_BLOCK_ID)) return Err; if (!SSIDs.empty()) return error("Invalid multiple synchronization scope names blocks"); SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (SSIDs.empty()) return error("Invalid empty synchronization scope names block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Synchronization scope names are implicitly mapped to synchronization // scope IDs by their order. Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); if (MaybeRecord.get() != bitc::SYNC_SCOPE_NAME) return error("Invalid record"); SmallString<16> SSN; if (convertToString(Record, 0, SSN)) return error("Invalid record"); SSIDs.push_back(Context.getOrInsertSyncScopeID(SSN)); Record.clear(); } } /// Associate a value with its name from the given index in the provided record. Expected BitcodeReader::recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT) { SmallString<128> ValueName; if (convertToString(Record, NameIndex, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; if (ValueID >= ValueList.size() || !ValueList[ValueID]) return error("Invalid record"); Value *V = ValueList[ValueID]; StringRef NameStr(ValueName.data(), ValueName.size()); if (NameStr.find_first_of(0) != StringRef::npos) return error("Invalid value name"); V->setName(NameStr); auto *GO = dyn_cast(V); if (GO) { if (GO->getComdat() == reinterpret_cast(1)) { if (TT.supportsCOMDAT()) GO->setComdat(TheModule->getOrInsertComdat(V->getName())); else GO->setComdat(nullptr); } } return V; } /// Helper to note and return the current location, and jump to the given /// offset. static Expected jumpToValueSymbolTable(uint64_t Offset, BitstreamCursor &Stream) { // Save the current parsing location so we can jump back at the end // of the VST read. uint64_t CurrentBit = Stream.GetCurrentBitNo(); if (Error JumpFailed = Stream.JumpToBit(Offset * 32)) return std::move(JumpFailed); Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); IGC_ASSERT(MaybeEntry.get().Kind == BitstreamEntry::SubBlock); IGC_ASSERT(MaybeEntry.get().ID == bitc::VALUE_SYMTAB_BLOCK_ID); return CurrentBit; } void BitcodeReader::setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F, ArrayRef Record) { // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. uint64_t FuncWordOffset = Record[1] - 1; uint64_t FuncBitOffset = FuncWordOffset * 32; DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta; // Set the LastFunctionBlockBit to point to the last function block. // Later when parsing is resumed after function materialization, // we can simply skip that last function block. if (FuncBitOffset > LastFunctionBlockBit) LastFunctionBlockBit = FuncBitOffset; } /// Read a new-style GlobalValue symbol table. Error BitcodeReader::parseGlobalValueSymbolTable() { unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Error Err = Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return Err; SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: break; } Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { case bitc::VST_CODE_FNENTRY: // [valueid, offset] setDeferredFunctionInfo(FuncBitcodeOffsetDelta, cast(ValueList[Record[0]]), Record); break; } } } /// Parse the value symbol table at either the current parsing location or /// at the given bit offset if provided. Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) { uint64_t CurrentBit; // Pass in the Offset to distinguish between calling for the module-level // VST (where we want to jump to the VST offset) and the function-level // VST (where we don't). if (Offset > 0) { Expected MaybeCurrentBit = jumpToValueSymbolTable(Offset, Stream); if (!MaybeCurrentBit) return MaybeCurrentBit.takeError(); CurrentBit = MaybeCurrentBit.get(); // If this module uses a string table, read this as a module-level VST. if (UseStrtab) { if (Error Err = parseGlobalValueSymbolTable()) return Err; if (Error JumpFailed = Stream.JumpToBit(CurrentBit)) return JumpFailed; return Error::success(); } // Otherwise, the VST will be in a similar format to a function-level VST, // and will contain symbol names. } // Compute the delta between the bitcode indices in the VST (the word offset // to the word-aligned ENTER_SUBBLOCK for the function block, and that // expected by the lazy reader. The reader's EnterSubBlock expects to have // already read the ENTER_SUBBLOCK code (size getAbbrevIDWidth) and BlockID // (size BlockIDWidth). Note that we access the stream's AbbrevID width here // just before entering the VST subblock because: 1) the EnterSubBlock // changes the AbbrevID width; 2) the VST block is nested within the same // outer MODULE_BLOCK as the FUNCTION_BLOCKs and therefore have the same // AbbrevID width before calling EnterSubBlock; and 3) when we want to // jump to the FUNCTION_BLOCK using this offset later, we don't want // to rely on the stream's AbbrevID width being that of the MODULE_BLOCK. unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Error Err = Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return Err; SmallVector Record; Triple TT(TheModule->getTargetTriple()); // Read all the records for this value table. SmallString<128> ValueName; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (Offset > 0) if (Error JumpFailed = Stream.JumpToBit(CurrentBit)) return JumpFailed; return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: unknown type. break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] Expected ValOrErr = recordValue(Record, 1, TT); if (Error Err = ValOrErr.takeError()) return Err; ValOrErr.get(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] Expected ValOrErr = recordValue(Record, 2, TT); if (Error Err = ValOrErr.takeError()) return Err; Value *V = ValOrErr.get(); // Ignore function offsets emitted for aliases of functions in older // versions of LLVM. if (auto *F = dyn_cast(V)) setDeferredFunctionInfo(FuncBitcodeOffsetDelta, F, Record); break; } case bitc::VST_CODE_BBENTRY: { if (convertToString(Record, 1, ValueName)) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[0]); if (!BB) return error("Invalid record"); BB->setName(StringRef(ValueName.data(), ValueName.size())); ValueName.clear(); break; } } } } /// Decode a signed value stored with the sign bit in the LSB for dense VBR /// encoding. uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) { if ((V & 1) == 0) return V >> 1; if (V != 1) return -(V >> 1); // There is no such thing as -0 with integers. "-0" really means MININT. return 1ULL << 63; } /// Resolve all of the initializers for global values and aliases that we can. Error BitcodeReader::resolveGlobalAndIndirectSymbolInits() { std::vector> GlobalInitWorklist; std::vector> IndirectSymbolInitWorklist; std::vector> FunctionPrefixWorklist; std::vector> FunctionPrologueWorklist; std::vector> FunctionPersonalityFnWorklist; GlobalInitWorklist.swap(GlobalInits); IndirectSymbolInitWorklist.swap(IndirectSymbolInits); FunctionPrefixWorklist.swap(FunctionPrefixes); FunctionPrologueWorklist.swap(FunctionPrologues); FunctionPersonalityFnWorklist.swap(FunctionPersonalityFns); while (!GlobalInitWorklist.empty()) { unsigned ValID = GlobalInitWorklist.back().second; if (ValID >= ValueList.size()) { // Not ready to resolve this yet, it requires something later in the file. GlobalInits.push_back(GlobalInitWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) GlobalInitWorklist.back().first->setInitializer(C); else return error("Expected a constant"); } GlobalInitWorklist.pop_back(); } while (!IndirectSymbolInitWorklist.empty()) { unsigned ValID = IndirectSymbolInitWorklist.back().second; if (ValID >= ValueList.size()) { IndirectSymbolInits.push_back(IndirectSymbolInitWorklist.back()); } else { Constant *C = dyn_cast_or_null(ValueList[ValID]); if (!C) return error("Expected a constant"); GlobalIndirectSymbol *GIS = IndirectSymbolInitWorklist.back().first; if (isa(GIS) && C->getType() != GIS->getType()) return error("Alias and aliasee types don't match"); GIS->setIndirectSymbol(C); } IndirectSymbolInitWorklist.pop_back(); } while (!FunctionPrefixWorklist.empty()) { unsigned ValID = FunctionPrefixWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrefixes.push_back(FunctionPrefixWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrefixWorklist.back().first->setPrefixData(C); else return error("Expected a constant"); } FunctionPrefixWorklist.pop_back(); } while (!FunctionPrologueWorklist.empty()) { unsigned ValID = FunctionPrologueWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrologues.push_back(FunctionPrologueWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrologueWorklist.back().first->setPrologueData(C); else return error("Expected a constant"); } FunctionPrologueWorklist.pop_back(); } while (!FunctionPersonalityFnWorklist.empty()) { unsigned ValID = FunctionPersonalityFnWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPersonalityFns.push_back(FunctionPersonalityFnWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPersonalityFnWorklist.back().first->setPersonalityFn(C); else return error("Expected a constant"); } FunctionPersonalityFnWorklist.pop_back(); } return Error::success(); } static APInt readWideAPInt(ArrayRef Vals, unsigned TypeBits) { SmallVector Words(Vals.size()); transform(Vals, Words.begin(), BitcodeReader::decodeSignRotatedValue); return APInt(TypeBits, Words); } Error BitcodeReader::parseConstants() { if (Error Err = Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID)) return Err; SmallVector Record; // Read all the records for this value table. Type *CurTy = Type::getInt32Ty(Context); Type *CurFullTy = Type::getInt32Ty(Context); unsigned NextCstNo = ValueList.size(); while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NextCstNo != ValueList.size()) return error("Invalid constant reference"); // Once all the constants have been read, go through and resolve forward // references. ValueList.resolveConstantForwardRefs(); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *VoidType = Type::getVoidTy(Context); Value *V = nullptr; Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (unsigned BitCode = MaybeBitCode.get()) { default: // Default behavior: unknown constant case bitc::CST_CODE_UNDEF: // UNDEF V = UndefValue::get(CurTy); break; case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid] if (Record.empty()) return error("Invalid record"); if (Record[0] >= TypeList.size() || !TypeList[Record[0]]) return error("Invalid record"); if (TypeList[Record[0]] == VoidType) return error("Invalid constant type"); CurFullTy = TypeList[Record[0]]; CurTy = flattenPointerTypes(CurFullTy); continue; // Skip the ValueList manipulation. case bitc::CST_CODE_NULL: // NULL if (CurTy->isVoidTy() || CurTy->isFunctionTy() || CurTy->isLabelTy()) return error("Invalid type for a constant null value"); V = Constant::getNullValue(CurTy); break; case bitc::CST_CODE_INTEGER: // INTEGER: [intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0])); break; case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); APInt VInt = readWideAPInt(Record, cast(CurTy)->getBitWidth()); V = ConstantInt::get(Context, VInt); break; } case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval] if (Record.empty()) return error("Invalid record"); if (CurTy->isHalfTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf(), APInt(16, (uint16_t)Record[0]))); else if (CurTy->isFloatTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle(), APInt(32, (uint32_t)Record[0]))); else if (CurTy->isDoubleTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble(), APInt(64, Record[0]))); else if (CurTy->isX86_FP80Ty()) { // Bits are not stored the same way as a normal i80 APInt, compensate. uint64_t Rearrange[2]; Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16); Rearrange[1] = Record[0] >> 48; V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended(), APInt(80, Rearrange))); } else if (CurTy->isFP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad(), APInt(128, Record))); else if (CurTy->isPPC_FP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble(), APInt(128, Record))); else V = UndefValue::get(CurTy); break; } case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number] if (Record.empty()) return error("Invalid record"); unsigned Size = Record.size(); SmallVector Elts; if (StructType *STy = dyn_cast(CurTy)) { for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); } else if (ArrayType *ATy = dyn_cast(CurTy)) { Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantArray::get(ATy, Elts); } else if (VectorType *VTy = dyn_cast(CurTy)) { Type *EltTy = VTy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantVector::get(Elts); } else { V = UndefValue::get(CurTy); } break; } case bitc::CST_CODE_STRING: // STRING: [values] case bitc::CST_CODE_CSTRING: { // CSTRING: [values] if (Record.empty()) return error("Invalid record"); SmallString<16> Elts(Record.begin(), Record.end()); V = ConstantDataArray::getString(Context, Elts, BitCode == bitc::CST_CODE_CSTRING); break; } case bitc::CST_CODE_DATA: {// DATA: [n x value] if (Record.empty()) return error("Invalid record"); Type *EltTy = cast(CurTy)->getElementType(); if (EltTy->isIntegerTy(8)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(16)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(32)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(64)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isHalfTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isFloatTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isDoubleTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else { return error("Invalid type for value"); } break; } case bitc::CST_CODE_CE_UNOP: { // CE_UNOP: [opcode, opval] if (Record.size() < 2) return error("Invalid record"); int Opc = getDecodedUnaryOpcode(Record[0], CurTy); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown unop. } else { Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); unsigned Flags = 0; V = ConstantExpr::get(Opc, LHS, Flags); } break; } case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[0], CurTy); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown binop. } else { Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy); unsigned Flags = 0; if (Record.size() >= 4) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoSignedWrap; if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoUnsignedWrap; } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[3] & (1 << bitc::PEO_EXACT)) Flags |= SDivOperator::IsExact; } } V = ConstantExpr::get(Opc, LHS, RHS, Flags); } break; } case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedCastOpcode(Record[0]); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown cast. } else { Type *OpTy = getTypeByID(Record[1]); if (!OpTy) return error("Invalid record"); Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy); V = upgradeBitCastExpr(Opc, Op, CurTy); if (!V) V = ConstantExpr::getCast(Opc, Op, CurTy); } break; } case bitc::CST_CODE_CE_INBOUNDS_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX: { // [ty, flags, n x // operands] unsigned OpNum = 0; Type *PointeeType = nullptr; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX || Record.size() % 2) PointeeType = getTypeByID(Record[OpNum++]); bool InBounds = false; Optional InRangeIndex; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX) { uint64_t Op = Record[OpNum++]; InBounds = Op & 1; InRangeIndex = Op >> 1; } else if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP) InBounds = true; SmallVector Elts; Type *Elt0FullTy = nullptr; while (OpNum != Record.size()) { if (!Elt0FullTy) Elt0FullTy = getFullyStructuredTypeByID(Record[OpNum]); Type *ElTy = getTypeByID(Record[OpNum++]); if (!ElTy) return error("Invalid record"); Elts.push_back(ValueList.getConstantFwdRef(Record[OpNum++], ElTy)); } if (Elts.size() < 1) return error("Invalid gep with no operands"); Type *ImplicitPointeeType = getPointerElementFlatType(Elt0FullTy->getScalarType()); if (!PointeeType) PointeeType = ImplicitPointeeType; else if (PointeeType != ImplicitPointeeType) return error("Explicit gep operator type does not match pointee type " "of pointer operand"); ArrayRef Indices(Elts.begin() + 1, Elts.end()); V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices, InBounds, InRangeIndex); break; } case bitc::CST_CODE_CE_SELECT: { // CE_SELECT: [opval#, opval#, opval#] if (Record.size() < 3) return error("Invalid record"); Type *SelectorTy = Type::getInt1Ty(Context); // The selector might be an i1 or an // Get the type from the ValueList before getting a forward ref. if (VectorType *VTy = dyn_cast(CurTy)) if (Value *V = ValueList[Record[0]]) if (SelectorTy != V->getType()) SelectorTy = VectorType::get(SelectorTy, VTy->getNumElements()); V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0], SelectorTy), ValueList.getConstantFwdRef(Record[1],CurTy), ValueList.getConstantFwdRef(Record[2],CurTy)); break; } case bitc::CST_CODE_CE_EXTRACTELT : { // CE_EXTRACTELT: [opty, opval, opty, opval] if (Record.size() < 3) return error("Invalid record"); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op1 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op1) return error("Invalid record"); V = ConstantExpr::getExtractElement(Op0, Op1); break; } case bitc::CST_CODE_CE_INSERTELT : { // CE_INSERTELT: [opval, opval, opty, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy->getElementType()); Constant *Op2 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op2 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op2) return error("Invalid record"); V = ConstantExpr::getInsertElement(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), OpTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval] VectorType *RTy = dyn_cast(CurTy); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (Record.size() < 4 || !RTy || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), RTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred] if (Record.size() < 4) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); if (OpTy->isFPOrFPVectorTy()) V = ConstantExpr::getFCmp(Record[3], Op0, Op1); else V = ConstantExpr::getICmp(Record[3], Op0, Op1); break; } // This maintains backward compatibility, pre-asm dialect keywords. // FIXME: Remove with the 4.0 release. case bitc::CST_CODE_INLINEASM_OLD: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = Record[0] >> 1; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; UpgradeInlineAsmString(&AsmStr); V = InlineAsm::get( cast(getPointerElementFlatType(CurFullTy)), AsmStr, ConstrStr, HasSideEffects, IsAlignStack); break; } // This version adds support for the asm dialect keywords (e.g., // inteldialect). case bitc::CST_CODE_INLINEASM: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = (Record[0] >> 1) & 1; unsigned AsmDialect = Record[0] >> 2; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; UpgradeInlineAsmString(&AsmStr); V = InlineAsm::get( cast(getPointerElementFlatType(CurFullTy)), AsmStr, ConstrStr, HasSideEffects, IsAlignStack, InlineAsm::AsmDialect(AsmDialect)); break; } case bitc::CST_CODE_BLOCKADDRESS:{ if (Record.size() < 3) return error("Invalid record"); Type *FnTy = getTypeByID(Record[0]); if (!FnTy) return error("Invalid record"); Function *Fn = dyn_cast_or_null(ValueList.getConstantFwdRef(Record[1],FnTy)); if (!Fn) return error("Invalid record"); // If the function is already parsed we can insert the block address right // away. BasicBlock *BB; unsigned BBID = Record[2]; if (!BBID) // Invalid reference to entry block. return error("Invalid ID"); if (!Fn->empty()) { Function::iterator BBI = Fn->begin(), BBE = Fn->end(); for (size_t I = 0, E = BBID; I != E; ++I) { if (BBI == BBE) return error("Invalid ID"); ++BBI; } BB = &*BBI; } else { // Otherwise insert a placeholder and remember it so it can be inserted // when the function is parsed. auto &FwdBBs = BasicBlockFwdRefs[Fn]; if (FwdBBs.empty()) BasicBlockFwdRefQueue.push_back(Fn); if (FwdBBs.size() < BBID + 1) FwdBBs.resize(BBID + 1); if (!FwdBBs[BBID]) FwdBBs[BBID] = BasicBlock::Create(Context); BB = FwdBBs[BBID]; } V = BlockAddress::get(Fn, BB); break; } } IGC_ASSERT(V->getType() == flattenPointerTypes(CurFullTy) && "Incorrect fully structured type provided for Constant"); ValueList.assignValue(V, NextCstNo, CurFullTy); ++NextCstNo; } } Error BitcodeReader::parseUseLists() { if (Error Err = Stream.EnterSubBlock(bitc::USELIST_BLOCK_ID)) return Err; // Read all the records. SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a use list record. Record.clear(); bool IsBB = false; Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: unknown type. break; case bitc::USELIST_CODE_BB: IsBB = true; LLVM_FALLTHROUGH; case bitc::USELIST_CODE_DEFAULT: { unsigned RecordLength = Record.size(); if (RecordLength < 3) // Records should have at least an ID and two indexes. return error("Invalid record"); unsigned ID = Record.back(); Record.pop_back(); Value *V; if (IsBB) { IGC_ASSERT(ID < FunctionBBs.size() && "Basic block not found"); V = FunctionBBs[ID]; } else V = ValueList[ID]; unsigned NumUses = 0; SmallDenseMap Order; for (const Use &U : V->materialized_uses()) { if (++NumUses > Record.size()) break; Order[&U] = Record[NumUses - 1]; } if (Order.size() != Record.size() || NumUses > Record.size()) // Mismatches can happen if the functions are being materialized lazily // (out-of-order), or a value has been upgraded. break; V->sortUseList([&](const Use &L, const Use &R) { return Order.lookup(&L) < Order.lookup(&R); }); break; } } } } /// When we see the block for metadata, remember where it is and then skip it. /// This lets us lazily deserialize the metadata. Error BitcodeReader::rememberAndSkipMetadata() { // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); DeferredMetadataInfo.push_back(CurBit); // Skip over the block for now. if (Error Err = Stream.SkipBlock()) return Err; return Error::success(); } Error BitcodeReader::materializeMetadata() { for (uint64_t BitPos : DeferredMetadataInfo) { // Move the bit stream to the saved position. if (Error JumpFailed = Stream.JumpToBit(BitPos)) return JumpFailed; if (Error Err = MDLoader->parseModuleMetadata()) return Err; } // Upgrade "Linker Options" module flag to "llvm.linker.options" module-level // metadata. if (Metadata *Val = TheModule->getModuleFlag("Linker Options")) { NamedMDNode *LinkerOpts = TheModule->getOrInsertNamedMetadata("llvm.linker.options"); for (const MDOperand &MDOptions : cast(Val)->operands()) LinkerOpts->addOperand(cast(MDOptions)); } DeferredMetadataInfo.clear(); return Error::success(); } void BitcodeReader::setStripDebugInfo() { StripDebugInfo = true; } /// When we see the block for a function body, remember where it is and then /// skip it. This lets us lazily deserialize the functions. Error BitcodeReader::rememberAndSkipFunctionBody() { // Get the function we are talking about. if (FunctionsWithBodies.empty()) return error("Insufficient function protos"); Function *Fn = FunctionsWithBodies.back(); FunctionsWithBodies.pop_back(); // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); IGC_ASSERT( (DeferredFunctionInfo[Fn] == 0 || DeferredFunctionInfo[Fn] == CurBit) && "Mismatch between VST and scanned function offsets"); DeferredFunctionInfo[Fn] = CurBit; // Skip over the function block for now. if (Error Err = Stream.SkipBlock()) return Err; return Error::success(); } Error BitcodeReader::globalCleanup() { // Patch the initializers for globals and aliases up. if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; if (!GlobalInits.empty() || !IndirectSymbolInits.empty()) return error("Malformed global initializer set"); // Look for intrinsic functions which need to be upgraded at some point for (Function &F : *TheModule) { MDLoader->upgradeDebugIntrinsics(F); Function *NewFn; if (UpgradeIntrinsicFunction(&F, NewFn)) UpgradedIntrinsics[&F] = NewFn; else if (auto Remangled = Intrinsic::remangleIntrinsicFunction(&F)) // Some types could be renamed during loading if several modules are // loaded in the same LLVMContext (LTO scenario). In this case we should // remangle intrinsics names as well. RemangledIntrinsics[&F] = Remangled.getValue(); } // Look for global variables which need to be renamed. std::vector> UpgradedVariables; for (GlobalVariable &GV : TheModule->globals()) if (GlobalVariable *Upgraded = UpgradeGlobalVariable(&GV)) UpgradedVariables.emplace_back(&GV, Upgraded); for (auto &Pair : UpgradedVariables) { Pair.first->eraseFromParent(); TheModule->getGlobalList().push_back(Pair.second); } // Force deallocation of memory for these vectors to favor the client that // want lazy deserialization. std::vector>().swap(GlobalInits); std::vector>().swap( IndirectSymbolInits); return Error::success(); } /// Support for lazy parsing of function bodies. This is required if we /// either have an old bitcode file without a VST forward declaration record, /// or if we have an anonymous function being materialized, since anonymous /// functions do not have a name and are therefore not in the VST. Error BitcodeReader::rememberAndSkipFunctionBodies() { if (Error JumpFailed = Stream.JumpToBit(NextUnreadBit)) return JumpFailed; if (Stream.AtEndOfStream()) return error("Could not find function in stream"); if (!SeenFirstFunctionBody) return error("Trying to materialize functions before seeing function blocks"); // An old bitcode file with the symbol table at the end would have // finished the parse greedily. IGC_ASSERT(SeenValueSymbolTable); SmallVector Record; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { default: return error("Expect SubBlock"); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: return error("Expect function block"); case bitc::FUNCTION_BLOCK_ID: if (Error Err = rememberAndSkipFunctionBody()) return Err; NextUnreadBit = Stream.GetCurrentBitNo(); return Error::success(); } } } } bool BitcodeReaderBase::readBlockInfo() { Expected> MaybeNewBlockInfo = Stream.ReadBlockInfoBlock(); if (!MaybeNewBlockInfo) return true; // FIXME Handle the error. Optional NewBlockInfo = std::move(MaybeNewBlockInfo.get()); if (!NewBlockInfo) return true; BlockInfo = std::move(*NewBlockInfo); return false; } Error BitcodeReader::parseComdatRecord(ArrayRef Record) { // v1: [selection_kind, name] // v2: [strtab_offset, strtab_size, selection_kind] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.empty()) return error("Invalid record"); Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]); std::string OldFormatName; if (!UseStrtab) { if (Record.size() < 2) return error("Invalid record"); unsigned ComdatNameSize = Record[1]; OldFormatName.reserve(ComdatNameSize); for (unsigned i = 0; i != ComdatNameSize; ++i) OldFormatName += (char)Record[2 + i]; Name = OldFormatName; } Comdat *C = TheModule->getOrInsertComdat(Name); C->setSelectionKind(SK); ComdatList.push_back(C); return Error::success(); } static void inferDSOLocal(GlobalValue *GV) { // infer dso_local from linkage and visibility if it is not encoded. if (GV->hasLocalLinkage() || (!GV->hasDefaultVisibility() && !GV->hasExternalWeakLinkage())) GV->setDSOLocal(true); } Error BitcodeReader::parseGlobalVarRecord(ArrayRef Record) { // v1: [pointer type, isconst, initid, linkage, alignment, section, // visibility, threadlocal, unnamed_addr, externally_initialized, // dllstorageclass, comdat, attributes, preemption specifier, // partition strtab offset, partition strtab size] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.size() < 6) return error("Invalid record"); Type *FullTy = getFullyStructuredTypeByID(Record[0]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); bool isConstant = Record[1] & 1; bool explicitType = Record[1] & 2; unsigned AddressSpace; if (explicitType) { AddressSpace = Record[1] >> 2; } else { if (!Ty->isPointerTy()) return error("Invalid type for value"); AddressSpace = cast(Ty)->getAddressSpace(); std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); } uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); MaybeAlign Alignment; if (Error Err = parseAlignmentValue(Record[4], Alignment)) return Err; std::string Section; if (Record[5]) { if (Record[5] - 1 >= SectionTable.size()) return error("Invalid ID"); Section = SectionTable[Record[5] - 1]; } GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; // Local linkage must have default visibility. if (Record.size() > 6 && !GlobalValue::isLocalLinkage(Linkage)) // FIXME: Change to an error if non-default in 4.0. Visibility = getDecodedVisibility(Record[6]); GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; if (Record.size() > 7) TLM = getDecodedThreadLocalMode(Record[7]); GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 8) UnnamedAddr = getDecodedUnnamedAddrType(Record[8]); bool ExternallyInitialized = false; if (Record.size() > 9) ExternallyInitialized = Record[9]; GlobalVariable *NewGV = new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, Name, nullptr, TLM, AddressSpace, ExternallyInitialized); NewGV->setAlignment(Alignment); if (!Section.empty()) NewGV->setSection(Section); NewGV->setVisibility(Visibility); NewGV->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10) NewGV->setDLLStorageClass(getDecodedDLLStorageClass(Record[10])); else upgradeDLLImportExportLinkage(NewGV, RawLinkage); FullTy = PointerType::get(FullTy, AddressSpace); IGC_ASSERT(NewGV->getType() == flattenPointerTypes(FullTy) && "Incorrect fully specified type for GlobalVariable"); ValueList.push_back(NewGV, FullTy); // Remember which value to use for the global initializer. if (unsigned InitID = Record[2]) GlobalInits.push_back(std::make_pair(NewGV, InitID - 1)); if (Record.size() > 11) { if (unsigned ComdatID = Record[11]) { if (ComdatID > ComdatList.size()) return error("Invalid global variable comdat ID"); NewGV->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { NewGV->setComdat(reinterpret_cast(1)); } if (Record.size() > 12) { auto AS = getAttributes(Record[12]).getFnAttributes(); NewGV->setAttributes(AS); } if (Record.size() > 13) { NewGV->setDSOLocal(getDecodedDSOLocal(Record[13])); } inferDSOLocal(NewGV); // Check whether we have enough values to read a partition name. if (Record.size() > 15) NewGV->setPartition(StringRef(Strtab.data() + Record[14], Record[15])); return Error::success(); } Error BitcodeReader::parseFunctionRecord(ArrayRef Record) { // v1: [type, callingconv, isproto, linkage, paramattr, alignment, section, // visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat, // prefixdata, personalityfn, preemption specifier, addrspace] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.size() < 8) return error("Invalid record"); Type *FullFTy = getFullyStructuredTypeByID(Record[0]); Type *FTy = flattenPointerTypes(FullFTy); if (!FTy) return error("Invalid record"); if (isa(FTy)) std::tie(FullFTy, FTy) = getPointerElementTypes(FullFTy); if (!isa(FTy)) return error("Invalid type for value"); auto CC = static_cast(Record[1]); if (CC & ~CallingConv::MaxID) return error("Invalid calling convention ID"); unsigned AddrSpace = TheModule->getDataLayout().getProgramAddressSpace(); if (Record.size() > 16) AddrSpace = Record[16]; Function *Func = Function::Create(cast(FTy), GlobalValue::ExternalLinkage, AddrSpace, Name, TheModule); IGC_ASSERT(Func->getFunctionType() == flattenPointerTypes(FullFTy) && "Incorrect fully specified type provided for function"); FunctionTypes[Func] = cast(FullFTy); Func->setCallingConv(CC); bool isProto = Record[2]; uint64_t RawLinkage = Record[3]; Func->setLinkage(getDecodedLinkage(RawLinkage)); Func->setAttributes(getAttributes(Record[4])); // Upgrade any old-style byval without a type by propagating the argument's // pointee type. There should be no opaque pointers where the byval type is // implicit. for (unsigned i = 0; i != Func->arg_size(); ++i) { if (!Func->hasParamAttribute(i, Attribute::ByVal)) continue; Type *PTy = cast(FullFTy)->getParamType(i); Func->removeParamAttr(i, Attribute::ByVal); Func->addParamAttr(i, Attribute::getWithByValType( Context, getPointerElementFlatType(PTy))); } MaybeAlign Alignment; if (Error Err = parseAlignmentValue(Record[5], Alignment)) return Err; Func->setAlignment(Alignment); if (Record[6]) { if (Record[6] - 1 >= SectionTable.size()) return error("Invalid ID"); Func->setSection(SectionTable[Record[6] - 1]); } // Local linkage must have default visibility. if (!Func->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. Func->setVisibility(getDecodedVisibility(Record[7])); if (Record.size() > 8 && Record[8]) { if (Record[8] - 1 >= GCTable.size()) return error("Invalid ID"); Func->setGC(GCTable[Record[8] - 1]); } GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 9) UnnamedAddr = getDecodedUnnamedAddrType(Record[9]); Func->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10 && Record[10] != 0) FunctionPrologues.push_back(std::make_pair(Func, Record[10] - 1)); if (Record.size() > 11) Func->setDLLStorageClass(getDecodedDLLStorageClass(Record[11])); else upgradeDLLImportExportLinkage(Func, RawLinkage); if (Record.size() > 12) { if (unsigned ComdatID = Record[12]) { if (ComdatID > ComdatList.size()) return error("Invalid function comdat ID"); Func->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { Func->setComdat(reinterpret_cast(1)); } if (Record.size() > 13 && Record[13] != 0) FunctionPrefixes.push_back(std::make_pair(Func, Record[13] - 1)); if (Record.size() > 14 && Record[14] != 0) FunctionPersonalityFns.push_back(std::make_pair(Func, Record[14] - 1)); if (Record.size() > 15) { Func->setDSOLocal(getDecodedDSOLocal(Record[15])); } inferDSOLocal(Func); // Record[16] is the address space number. // Check whether we have enough values to read a partition name. if (Record.size() > 18) Func->setPartition(StringRef(Strtab.data() + Record[17], Record[18])); Type *FullTy = PointerType::get(FullFTy, AddrSpace); IGC_ASSERT(Func->getType() == flattenPointerTypes(FullTy) && "Incorrect fully specified type provided for Function"); ValueList.push_back(Func, FullTy); // If this is a function with a body, remember the prototype we are // creating now, so that we can match up the body with them later. if (!isProto) { Func->setIsMaterializable(true); FunctionsWithBodies.push_back(Func); DeferredFunctionInfo[Func] = 0; } return Error::success(); } Error BitcodeReader::parseGlobalIndirectSymbolRecord( unsigned BitCode, ArrayRef Record) { // v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST) // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, // dllstorageclass, threadlocal, unnamed_addr, // preemption specifier] (name in VST) // v1 IFUNC: [alias type, addrspace, aliasee val#, linkage, // visibility, dllstorageclass, threadlocal, unnamed_addr, // preemption specifier] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD; if (Record.size() < (3 + (unsigned)NewRecord)) return error("Invalid record"); unsigned OpNum = 0; Type *FullTy = getFullyStructuredTypeByID(Record[OpNum++]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); unsigned AddrSpace; if (!NewRecord) { auto *PTy = dyn_cast(Ty); if (!PTy) return error("Invalid type for value"); std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); AddrSpace = PTy->getAddressSpace(); } else { AddrSpace = Record[OpNum++]; } auto Val = Record[OpNum++]; auto Linkage = Record[OpNum++]; GlobalIndirectSymbol *NewGA; if (BitCode == bitc::MODULE_CODE_ALIAS || BitCode == bitc::MODULE_CODE_ALIAS_OLD) NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name, TheModule); else NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name, nullptr, TheModule); IGC_ASSERT(NewGA->getValueType() == flattenPointerTypes(FullTy) && "Incorrect fully structured type provided for GlobalIndirectSymbol"); // Old bitcode files didn't have visibility field. // Local linkage must have default visibility. if (OpNum != Record.size()) { auto VisInd = OpNum++; if (!NewGA->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. NewGA->setVisibility(getDecodedVisibility(Record[VisInd])); } if (BitCode == bitc::MODULE_CODE_ALIAS || BitCode == bitc::MODULE_CODE_ALIAS_OLD) { if (OpNum != Record.size()) NewGA->setDLLStorageClass(getDecodedDLLStorageClass(Record[OpNum++])); else upgradeDLLImportExportLinkage(NewGA, Linkage); if (OpNum != Record.size()) NewGA->setThreadLocalMode(getDecodedThreadLocalMode(Record[OpNum++])); if (OpNum != Record.size()) NewGA->setUnnamedAddr(getDecodedUnnamedAddrType(Record[OpNum++])); } if (OpNum != Record.size()) NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++])); inferDSOLocal(NewGA); // Check whether we have enough values to read a partition name. if (OpNum + 1 < Record.size()) { NewGA->setPartition( StringRef(Strtab.data() + Record[OpNum], Record[OpNum + 1])); OpNum += 2; } FullTy = PointerType::get(FullTy, AddrSpace); IGC_ASSERT(NewGA->getType() == flattenPointerTypes(FullTy) && "Incorrect fully structured type provided for GlobalIndirectSymbol"); ValueList.push_back(NewGA, FullTy); IndirectSymbolInits.push_back(std::make_pair(NewGA, Val)); return Error::success(); } Error BitcodeReader::parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata) { if (ResumeBit) { if (Error JumpFailed = Stream.JumpToBit(ResumeBit)) return JumpFailed; } else if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return Err; SmallVector Record; // Read all the records for this module. while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return globalCleanup(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Error Err = Stream.SkipBlock()) return Err; break; case bitc::BLOCKINFO_BLOCK_ID: if (readBlockInfo()) return error("Malformed block"); break; case bitc::PARAMATTR_BLOCK_ID: if (Error Err = parseAttributeBlock()) return Err; break; case bitc::PARAMATTR_GROUP_BLOCK_ID: if (Error Err = parseAttributeGroupBlock()) return Err; break; case bitc::TYPE_BLOCK_ID_NEW: if (Error Err = parseTypeTable()) return Err; break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (!SeenValueSymbolTable) { // Either this is an old form VST without function index and an // associated VST forward declaration record (which would have caused // the VST to be jumped to and parsed before it was encountered // normally in the stream), or there were no function blocks to // trigger an earlier parsing of the VST. IGC_ASSERT(VSTOffset == 0 || FunctionsWithBodies.empty()); if (Error Err = parseValueSymbolTable()) return Err; SeenValueSymbolTable = true; } else { // We must have had a VST forward declaration record, which caused // the parser to jump to and parse the VST earlier. IGC_ASSERT(VSTOffset > 0); if (Error Err = Stream.SkipBlock()) return Err; } break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; break; case bitc::METADATA_BLOCK_ID: if (ShouldLazyLoadMetadata) { if (Error Err = rememberAndSkipMetadata()) return Err; break; } IGC_ASSERT(DeferredMetadataInfo.empty() && "Unexpected deferred metadata"); if (Error Err = MDLoader->parseModuleMetadata()) return Err; break; case bitc::METADATA_KIND_BLOCK_ID: if (Error Err = MDLoader->parseMetadataKinds()) return Err; break; case bitc::FUNCTION_BLOCK_ID: // If this is the first function body we've seen, reverse the // FunctionsWithBodies list. if (!SeenFirstFunctionBody) { std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end()); if (Error Err = globalCleanup()) return Err; SeenFirstFunctionBody = true; } if (VSTOffset > 0) { // If we have a VST forward declaration record, make sure we // parse the VST now if we haven't already. It is needed to // set up the DeferredFunctionInfo vector for lazy reading. if (!SeenValueSymbolTable) { if (Error Err = BitcodeReader::parseValueSymbolTable(VSTOffset)) return Err; SeenValueSymbolTable = true; // Fall through so that we record the NextUnreadBit below. // This is necessary in case we have an anonymous function that // is later materialized. Since it will not have a VST entry we // need to fall back to the lazy parse to find its offset. } else { // If we have a VST forward declaration record, but have already // parsed the VST (just above, when the first function body was // encountered here), then we are resuming the parse after // materializing functions. The ResumeBit points to the // start of the last function block recorded in the // DeferredFunctionInfo map. Skip it. if (Error Err = Stream.SkipBlock()) return Err; continue; } } // Support older bitcode files that did not have the function // index in the VST, nor a VST forward declaration record, as // well as anonymous functions that do not have VST entries. // Build the DeferredFunctionInfo vector on the fly. if (Error Err = rememberAndSkipFunctionBody()) return Err; // Suspend parsing when we reach the function bodies. Subsequent // materialization calls will resume it when necessary. If the bitcode // file is old, the symbol table will be at the end instead and will not // have been seen yet. In this case, just finish the parse now. if (SeenValueSymbolTable) { NextUnreadBit = Stream.GetCurrentBitNo(); // After the VST has been parsed, we need to make sure intrinsic name // are auto-upgraded. return globalCleanup(); } break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: if (Error Err = parseOperandBundleTags()) return Err; break; case bitc::SYNC_SCOPE_NAMES_BLOCK_ID: if (Error Err = parseSyncScopeNames()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (unsigned BitCode = MaybeBitCode.get()) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { Expected VersionOrErr = parseVersionRecord(Record); if (!VersionOrErr) return VersionOrErr.takeError(); UseRelativeIDs = *VersionOrErr >= 1; break; } case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setTargetTriple(S); break; } case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); size_t index = S.find("-a64:64:64"); if (index != std::string::npos) S.replace(index, 10, ""); TheModule->setDataLayout(S); break; } case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setModuleInlineAsm(S); break; } case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N] // FIXME: Remove in 4.0. std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Ignore value. break; } case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); SectionTable.push_back(S); break; } case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); GCTable.push_back(S); break; } case bitc::MODULE_CODE_COMDAT: if (Error Err = parseComdatRecord(Record)) return Err; break; case bitc::MODULE_CODE_GLOBALVAR: if (Error Err = parseGlobalVarRecord(Record)) return Err; break; case bitc::MODULE_CODE_FUNCTION: if (Error Err = parseFunctionRecord(Record)) return Err; break; case bitc::MODULE_CODE_IFUNC: case bitc::MODULE_CODE_ALIAS: case bitc::MODULE_CODE_ALIAS_OLD: if (Error Err = parseGlobalIndirectSymbolRecord(BitCode, Record)) return Err; break; /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); TheModule->setSourceFileName(ValueName); break; } Record.clear(); // Upgrade data layout string. std::string DL = llvm::UpgradeDataLayoutString( TheModule->getDataLayoutStr(), TheModule->getTargetTriple()); TheModule->setDataLayout(DL); } } Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata, bool IsImporting) { TheModule = M; MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting, [&](unsigned ID) { return getTypeByID(ID); }); return parseModule(0, ShouldLazyLoadMetadata); } Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) { if (!isa(PtrType)) return error("Load/Store operand is not a pointer type"); Type *ElemType = cast(PtrType)->getElementType(); if (ValType && ValType != ElemType) return error("Explicit load/store type does not match pointee " "type of pointer operand"); if (!PointerType::isLoadableOrStorableType(ElemType)) return error("Cannot load/store from pointer"); return Error::success(); } void BitcodeReader::propagateByValTypes(CallBase *CB, ArrayRef ArgsFullTys) { for (unsigned i = 0; i != CB->arg_size(); ++i) { if (!CB->paramHasAttr(i, Attribute::ByVal)) continue; CB->removeParamAttr(i, Attribute::ByVal); CB->addParamAttr( i, Attribute::getWithByValType( Context, getPointerElementFlatType(ArgsFullTys[i]))); } } /// Lazily parse the specified function body block. Error BitcodeReader::parseFunctionBody(Function *F) { if (Error Err = Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID)) return Err; // Unexpected unresolved metadata when parsing function. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: incoming forward references"); InstructionList.clear(); unsigned ModuleValueListSize = ValueList.size(); unsigned ModuleMDLoaderSize = MDLoader->size(); // Add all the function arguments to the value table. unsigned ArgNo = 0; FunctionType *FullFTy = FunctionTypes[F]; for (Argument &I : F->args()) { IGC_ASSERT(I.getType() == flattenPointerTypes(FullFTy->getParamType(ArgNo)) && "Incorrect fully specified type for Function Argument"); ValueList.push_back(&I, FullFTy->getParamType(ArgNo++)); } unsigned NextValueNo = ValueList.size(); BasicBlock *CurBB = nullptr; unsigned CurBBNo = 0; DebugLoc LastLoc; auto getLastInstruction = [&]() -> Instruction * { if (CurBB && !CurBB->empty()) return &CurBB->back(); else if (CurBBNo && FunctionBBs[CurBBNo - 1] && !FunctionBBs[CurBBNo - 1]->empty()) return &FunctionBBs[CurBBNo - 1]->back(); return nullptr; }; std::vector OperandBundles; // Read all the records. SmallVector Record; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: goto OutOfRecordLoop; case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Error Err = Stream.SkipBlock()) return Err; break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; NextValueNo = ValueList.size(); break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (Error Err = parseValueSymbolTable()) return Err; break; case bitc::METADATA_ATTACHMENT_ID: if (Error Err = MDLoader->parseMetadataAttachment(*F, InstructionList)) return Err; break; case bitc::METADATA_BLOCK_ID: IGC_ASSERT(DeferredMetadataInfo.empty() && "Must read all module-level metadata before function-level"); if (Error Err = MDLoader->parseFunctionMetadata()) return Err; break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Instruction *I = nullptr; Type *FullTy = nullptr; Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (unsigned BitCode = MaybeBitCode.get()) { default: // Default behavior: reject return error("Invalid value"); case bitc::FUNC_CODE_DECLAREBLOCKS: { // DECLAREBLOCKS: [nblocks] if (Record.size() < 1 || Record[0] == 0) return error("Invalid record"); // Create all the basic blocks for the function. FunctionBBs.resize(Record[0]); // See if anything took the address of blocks in this function. auto BBFRI = BasicBlockFwdRefs.find(F); if (BBFRI == BasicBlockFwdRefs.end()) { for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i) FunctionBBs[i] = BasicBlock::Create(Context, "", F); } else { auto &BBRefs = BBFRI->second; // Check for invalid basic block references. if (BBRefs.size() > FunctionBBs.size()) return error("Invalid ID"); IGC_ASSERT(!BBRefs.empty() && "Unexpected empty array"); IGC_ASSERT(!BBRefs.front() && "Invalid reference to entry block"); for (unsigned I = 0, E = FunctionBBs.size(), RE = BBRefs.size(); I != E; ++I) if (I < RE && BBRefs[I]) { BBRefs[I]->insertInto(F); FunctionBBs[I] = BBRefs[I]; } else { FunctionBBs[I] = BasicBlock::Create(Context, "", F); } // Erase from the table. BasicBlockFwdRefs.erase(BBFRI); } CurBB = FunctionBBs[0]; continue; } case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN // This record indicates that the last instruction is at the same // location as the previous instruction with a location. I = getLastInstruction(); if (!I) return error("Invalid record"); I->setDebugLoc(LastLoc); I = nullptr; continue; case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia] I = getLastInstruction(); if (!I || Record.size() < 4) return error("Invalid record"); unsigned Line = Record[0], Col = Record[1]; unsigned ScopeID = Record[2], IAID = Record[3]; bool isImplicitCode = Record.size() == 5 && Record[4]; MDNode *Scope = nullptr, *IA = nullptr; if (ScopeID) { Scope = dyn_cast_or_null( MDLoader->getMetadataFwdRefOrLoad(ScopeID - 1)); if (!Scope) return error("Invalid record"); } if (IAID) { IA = dyn_cast_or_null( MDLoader->getMetadataFwdRefOrLoad(IAID - 1)); if (!IA) return error("Invalid record"); } LastLoc = DebugLoc::get(Line, Col, Scope, IA, isImplicitCode); I->setDebugLoc(LastLoc); I = nullptr; continue; } case bitc::FUNC_CODE_INST_UNOP: { // UNOP: [opval, ty, opcode] unsigned OpNum = 0; Value *LHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || OpNum+1 > Record.size()) return error("Invalid record"); int Opc = getDecodedUnaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return error("Invalid record"); I = UnaryOperator::Create((Instruction::UnaryOps)Opc, LHS); InstructionList.push_back(I); if (OpNum < Record.size()) { if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } } break; } case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode] unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS) || OpNum+1 > Record.size()) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return error("Invalid record"); I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); InstructionList.push_back(I); if (OpNum < Record.size()) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) cast(I)->setHasNoSignedWrap(true); if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) cast(I)->setHasNoUnsignedWrap(true); } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } else if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } } break; } case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || OpNum+2 != Record.size()) return error("Invalid record"); FullTy = getFullyStructuredTypeByID(Record[OpNum]); Type *ResTy = flattenPointerTypes(FullTy); int Opc = getDecodedCastOpcode(Record[OpNum + 1]); if (Opc == -1 || !ResTy) return error("Invalid record"); Instruction *Temp = nullptr; if ((I = UpgradeBitCastInst(Opc, Op, ResTy, Temp))) { if (Temp) { InstructionList.push_back(Temp); IGC_ASSERT(CurBB && "No current BB?"); CurBB->getInstList().push_back(Temp); } } else { auto CastOp = (Instruction::CastOps)Opc; if (!CastInst::castIsValid(CastOp, Op, ResTy)) return error("Invalid cast"); I = CastInst::Create(CastOp, Op, ResTy); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD: case bitc::FUNC_CODE_INST_GEP_OLD: case bitc::FUNC_CODE_INST_GEP: { // GEP: type, [n x operands] unsigned OpNum = 0; Type *Ty; bool InBounds; if (BitCode == bitc::FUNC_CODE_INST_GEP) { InBounds = Record[OpNum++]; FullTy = getFullyStructuredTypeByID(Record[OpNum++]); Ty = flattenPointerTypes(FullTy); } else { InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD; Ty = nullptr; } Value *BasePtr; Type *FullBaseTy = nullptr; if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr, &FullBaseTy)) return error("Invalid record"); if (!Ty) { std::tie(FullTy, Ty) = getPointerElementTypes(FullBaseTy->getScalarType()); } else if (Ty != getPointerElementFlatType(FullBaseTy->getScalarType())) return error( "Explicit gep type does not match pointee type of pointer operand"); SmallVector GEPIdx; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); GEPIdx.push_back(Op); } I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx); FullTy = GetElementPtrInst::getGEPReturnType(FullTy, I, GEPIdx); InstructionList.push_back(I); if (InBounds) cast(I)->setIsInBounds(true); break; } case bitc::FUNC_CODE_INST_EXTRACTVAL: { // EXTRACTVAL: [opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg, &FullTy)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("EXTRACTVAL: Invalid instruction with 0 indices"); SmallVector EXTRACTVALIdx; for (; OpNum != RecSize; ++OpNum) { bool IsArray = FullTy->isArrayTy(); bool IsStruct = FullTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("EXTRACTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= FullTy->getStructNumElements()) return error("EXTRACTVAL: Invalid struct index"); if (IsArray && Index >= FullTy->getArrayNumElements()) return error("EXTRACTVAL: Invalid array index"); EXTRACTVALIdx.push_back((unsigned)Index); if (IsStruct) FullTy = FullTy->getStructElementType(Index); else FullTy = FullTy->getArrayElementType(); } I = ExtractValueInst::Create(Agg, EXTRACTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTVAL: { // INSERTVAL: [opty, opval, opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg, &FullTy)) return error("Invalid record"); Value *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Val)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("INSERTVAL: Invalid instruction with 0 indices"); SmallVector INSERTVALIdx; Type *CurTy = Agg->getType(); for (; OpNum != RecSize; ++OpNum) { bool IsArray = CurTy->isArrayTy(); bool IsStruct = CurTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("INSERTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= CurTy->getStructNumElements()) return error("INSERTVAL: Invalid struct index"); if (IsArray && Index >= CurTy->getArrayNumElements()) return error("INSERTVAL: Invalid array index"); INSERTVALIdx.push_back((unsigned)Index); if (IsStruct) CurTy = CurTy->getStructElementType(Index); else CurTy = CurTy->getArrayElementType(); } if (CurTy != Val->getType()) return error("Inserted value type doesn't match aggregate type"); I = InsertValueInst::Create(Agg, Val, INSERTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval] // obsolete form of select // handles select i1 ... in old bitcode unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal, &FullTy) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || popValue(Record, OpNum, NextValueNo, Type::getInt1Ty(Context), Cond)) return error("Invalid record"); I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred] // new form of select // handles select i1 or select [N x i1] unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal, &FullTy) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || getValueTypePair(Record, OpNum, NextValueNo, Cond)) return error("Invalid record"); // select condition can be either i1 or [N x i1] if (VectorType* vector_type = dyn_cast(Cond->getType())) { // expect if (vector_type->getElementType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } else { // expect i1 if (Cond->getType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); if (OpNum < Record.size() && isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } break; } case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval] unsigned OpNum = 0; Value *Vec, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec, &FullTy) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); I = ExtractElementInst::Create(Vec, Idx); FullTy = FullTy->getVectorElementType(); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval] unsigned OpNum = 0; Value *Vec, *Elt, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec, &FullTy)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); if (popValue(Record, OpNum, NextValueNo, cast(Vec->getType())->getElementType(), Elt) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); I = InsertElementInst::Create(Vec, Elt, Idx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval] unsigned OpNum = 0; Value *Vec1, *Vec2, *Mask; if (getValueTypePair(Record, OpNum, NextValueNo, Vec1, &FullTy) || popValue(Record, OpNum, NextValueNo, Vec1->getType(), Vec2)) return error("Invalid record"); if (getValueTypePair(Record, OpNum, NextValueNo, Mask)) return error("Invalid record"); if (!Vec1->getType()->isVectorTy() || !Vec2->getType()->isVectorTy()) return error("Invalid type for value"); I = new ShuffleVectorInst(Vec1, Vec2, Mask); FullTy = VectorType::get(FullTy->getVectorElementType(), Mask->getType()->getVectorNumElements()); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred] // Old form of ICmp/FCmp returning bool // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were // both legal on vectors but had different behaviour. case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred] // FCmp/ICmp returning bool or vector of bool unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS)) return error("Invalid record"); if (OpNum >= Record.size()) return error( "Invalid record: operand number exceeded available operands"); unsigned PredVal = Record[OpNum]; bool IsFP = LHS->getType()->isFPOrFPVectorTy(); FastMathFlags FMF; if (IsFP && Record.size() > OpNum+1) FMF = getDecodedFastMathFlags(Record[++OpNum]); if (OpNum+1 != Record.size()) return error("Invalid record"); if (LHS->getType()->isFPOrFPVectorTy()) I = new FCmpInst((FCmpInst::Predicate)PredVal, LHS, RHS); else I = new ICmpInst((ICmpInst::Predicate)PredVal, LHS, RHS); if (FMF.any()) I->setFastMathFlags(FMF); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval] { unsigned Size = Record.size(); if (Size == 0) { I = ReturnInst::Create(Context); InstructionList.push_back(I); break; } unsigned OpNum = 0; Value *Op = nullptr; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); if (OpNum != Record.size()) return error("Invalid record"); I = ReturnInst::Create(Context, Op); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#] if (Record.size() != 1 && Record.size() != 3) return error("Invalid record"); BasicBlock *TrueDest = getBasicBlock(Record[0]); if (!TrueDest) return error("Invalid record"); if (Record.size() == 1) { I = BranchInst::Create(TrueDest); InstructionList.push_back(I); } else { BasicBlock *FalseDest = getBasicBlock(Record[1]); Value *Cond = getValue(Record, 2, NextValueNo, Type::getInt1Ty(Context)); if (!FalseDest || !Cond) return error("Invalid record"); I = BranchInst::Create(TrueDest, FalseDest, Cond); InstructionList.push_back(I); } break; } case bitc::FUNC_CODE_INST_CLEANUPRET: { // CLEANUPRET: [val] or [val,bb#] if (Record.size() != 1 && Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CleanupPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CleanupPad) return error("Invalid record"); BasicBlock *UnwindDest = nullptr; if (Record.size() == 2) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } I = CleanupReturnInst::Create(CleanupPad, UnwindDest); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHRET: { // CATCHRET: [val,bb#] if (Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CatchPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CatchPad) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); I = CatchReturnInst::Create(CatchPad, BB); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHSWITCH: { // CATCHSWITCH: [tok,num,(bb)*,bb?] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumHandlers = Record[Idx++]; SmallVector Handlers; for (unsigned Op = 0; Op != NumHandlers; ++Op) { BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); Handlers.push_back(BB); } BasicBlock *UnwindDest = nullptr; if (Idx + 1 == Record.size()) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } if (Record.size() != Idx) return error("Invalid record"); auto *CatchSwitch = CatchSwitchInst::Create(ParentPad, UnwindDest, NumHandlers); for (BasicBlock *Handler : Handlers) CatchSwitch->addHandler(Handler); I = CatchSwitch; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHPAD: case bitc::FUNC_CODE_INST_CLEANUPPAD: { // [tok,num,(ty,val)*] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumArgOperands = Record[Idx++]; SmallVector Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); Args.push_back(Val); } if (Record.size() != Idx) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_CLEANUPPAD) I = CleanupPadInst::Create(ParentPad, Args); else I = CatchPadInst::Create(ParentPad, Args); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...] // Check magic if ((Record[0] >> 16) == SWITCH_INST_MAGIC) { // "New" SwitchInst format with case ranges. The changes to write this // format were reverted but we still recognize bitcode that uses it. // Hopefully someday we will have support for case ranges and can use // this format again. Type *OpTy = getTypeByID(Record[1]); unsigned ValueBitWidth = cast(OpTy)->getBitWidth(); Value *Cond = getValue(Record, 2, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[3]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = Record[4]; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); unsigned CurIdx = 5; for (unsigned i = 0; i != NumCases; ++i) { SmallVector CaseVals; unsigned NumItems = Record[CurIdx++]; for (unsigned ci = 0; ci != NumItems; ++ci) { bool isSingleNumber = Record[CurIdx++]; APInt Low; unsigned ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; Low = readWideAPInt(makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; if (!isSingleNumber) { ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; APInt High = readWideAPInt( makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; // FIXME: It is not clear whether values in the range should be // compared as signed or unsigned values. The partially // implemented changes that used this format in the past used // unsigned comparisons. for ( ; Low.ule(High); ++Low) CaseVals.push_back(ConstantInt::get(Context, Low)); } else CaseVals.push_back(ConstantInt::get(Context, Low)); } BasicBlock *DestBB = getBasicBlock(Record[CurIdx++]); for (SmallVector::iterator cvi = CaseVals.begin(), cve = CaseVals.end(); cvi != cve; ++cvi) SI->addCase(*cvi, DestBB); } I = SI; break; } // Old SwitchInst format without case ranges. if (Record.size() < 3 || (Record.size() & 1) == 0) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Cond = getValue(Record, 1, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[2]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = (Record.size()-3)/2; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); for (unsigned i = 0, e = NumCases; i != e; ++i) { ConstantInt *CaseVal = dyn_cast_or_null(getFnValueByID(Record[3+i*2], OpTy)); BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]); if (!CaseVal || !DestBB) { delete SI; return error("Invalid record"); } SI->addCase(CaseVal, DestBB); } I = SI; break; } case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...] if (Record.size() < 2) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Address = getValue(Record, 1, NextValueNo, OpTy); if (!OpTy || !Address) return error("Invalid record"); unsigned NumDests = Record.size()-2; IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests); InstructionList.push_back(IBI); for (unsigned i = 0, e = NumDests; i != e; ++i) { if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) { IBI->addDestination(DestBB); } else { delete IBI; return error("Invalid record"); } } I = IBI; break; } case bitc::FUNC_CODE_INST_INVOKE: { // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...] if (Record.size() < 4) return error("Invalid record"); unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; BasicBlock *NormalBB = getBasicBlock(Record[OpNum++]); BasicBlock *UnwindBB = getBasicBlock(Record[OpNum++]); FunctionType *FTy = nullptr; FunctionType *FullFTy = nullptr; if ((CCInfo >> 13) & 1) { FullFTy = dyn_cast(getFullyStructuredTypeByID(Record[OpNum++])); if (!FullFTy) return error("Explicit invoke type is not a function type"); FTy = cast(flattenPointerTypes(FullFTy)); } Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee, &FullTy)) return error("Invalid record"); PointerType *CalleeTy = dyn_cast(Callee->getType()); if (!CalleeTy) return error("Callee is not a pointer"); if (!FTy) { FullFTy = dyn_cast(cast(FullTy)->getElementType()); if (!FullFTy) return error("Callee is not of pointer to function type"); FTy = cast(flattenPointerTypes(FullFTy)); } else if (getPointerElementFlatType(FullTy) != FTy) return error("Explicit invoke type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Ops; SmallVector ArgsFullTys; for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { Ops.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); ArgsFullTys.push_back(FullFTy->getParamType(i)); if (!Ops.back()) return error("Invalid record"); } if (!FTy->isVarArg()) { if (Record.size() != OpNum) return error("Invalid record"); } else { // Read type/value pairs for varargs params. while (OpNum != Record.size()) { Value *Op; Type *FullTy; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy)) return error("Invalid record"); Ops.push_back(Op); ArgsFullTys.push_back(FullTy); } } I = InvokeInst::Create(FTy, Callee, NormalBB, UnwindBB, Ops, OperandBundles); FullTy = FullFTy->getReturnType(); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast(CallingConv::MaxID & CCInfo)); cast(I)->setAttributes(PAL); propagateByValTypes(cast(I), ArgsFullTys); break; } case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval] unsigned Idx = 0; Value *Val = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); I = ResumeInst::Create(Val); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CALLBR: { // CALLBR: [attr, cc, norm, transfs, fty, fnid, args] unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; BasicBlock *DefaultDest = getBasicBlock(Record[OpNum++]); unsigned NumIndirectDests = Record[OpNum++]; SmallVector IndirectDests; for (unsigned i = 0, e = NumIndirectDests; i != e; ++i) IndirectDests.push_back(getBasicBlock(Record[OpNum++])); FunctionType *FTy = nullptr; FunctionType *FullFTy = nullptr; if ((CCInfo >> bitc::CALL_EXPLICIT_TYPE) & 1) { FullFTy = dyn_cast(getFullyStructuredTypeByID(Record[OpNum++])); if (!FullFTy) return error("Explicit call type is not a function type"); FTy = cast(flattenPointerTypes(FullFTy)); } Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee, &FullTy)) return error("Invalid record"); PointerType *OpTy = dyn_cast(Callee->getType()); if (!OpTy) return error("Callee is not a pointer type"); if (!FTy) { FullFTy = dyn_cast(cast(FullTy)->getElementType()); if (!FullFTy) return error("Callee is not of pointer to function type"); FTy = cast(flattenPointerTypes(FullFTy)); } else if (getPointerElementFlatType(FullTy) != FTy) return error("Explicit call type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Args; // Read the fixed params. for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { if (FTy->getParamType(i)->isLabelTy()) Args.push_back(getBasicBlock(Record[OpNum])); else Args.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); if (!Args.back()) return error("Invalid record"); } // Read type/value pairs for varargs params. if (!FTy->isVarArg()) { if (OpNum != Record.size()) return error("Invalid record"); } else { while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Args.push_back(Op); } } I = CallBrInst::Create(FTy, Callee, DefaultDest, IndirectDests, Args, OperandBundles); FullTy = FullFTy->getReturnType(); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast((0x7ff & CCInfo) >> bitc::CALL_CCONV)); cast(I)->setAttributes(PAL); break; } case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE I = new UnreachableInst(Context); InstructionList.push_back(I); break; case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] if (Record.size() < 1) return error("Invalid record"); // The first record specifies the type. FullTy = getFullyStructuredTypeByID(Record[0]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); // Phi arguments are pairs of records of [value, basic block]. // There is an optional final record for fast-math-flags if this phi has a // floating-point type. size_t NumArgs = (Record.size() - 1) / 2; PHINode *PN = PHINode::Create(Ty, NumArgs); if ((Record.size() - 1) % 2 == 1 && !isa(PN)) return error("Invalid record"); InstructionList.push_back(PN); for (unsigned i = 0; i != NumArgs; i++) { Value *V; // With the new function encoding, it is possible that operands have // negative IDs (for forward references). Use a signed VBR // representation to keep the encoding small. if (UseRelativeIDs) V = getValueSigned(Record, i * 2 + 1, NextValueNo, Ty); else V = getValue(Record, i * 2 + 1, NextValueNo, Ty); BasicBlock *BB = getBasicBlock(Record[i * 2 + 2]); if (!V || !BB) return error("Invalid record"); PN->addIncoming(V, BB); } I = PN; // If there are an even number of records, the final record must be FMF. if (Record.size() % 2 == 0) { IGC_ASSERT(isa(I) && "Unexpected phi type"); FastMathFlags FMF = getDecodedFastMathFlags(Record[Record.size() - 1]); if (FMF.any()) I->setFastMathFlags(FMF); } break; } case bitc::FUNC_CODE_INST_LANDINGPAD: case bitc::FUNC_CODE_INST_LANDINGPAD_OLD: { // LANDINGPAD: [ty, val, val, num, (id0,val0 ...)?] unsigned Idx = 0; if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD) { if (Record.size() < 3) return error("Invalid record"); } else { IGC_ASSERT(BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD); if (Record.size() < 4) return error("Invalid record"); } FullTy = getFullyStructuredTypeByID(Record[Idx++]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD) { Value *PersFn = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, PersFn)) return error("Invalid record"); if (!F->hasPersonalityFn()) F->setPersonalityFn(cast(PersFn)); else if (F->getPersonalityFn() != cast(PersFn)) return error("Personality function mismatch"); } bool IsCleanup = !!Record[Idx++]; unsigned NumClauses = Record[Idx++]; LandingPadInst *LP = LandingPadInst::Create(Ty, NumClauses); LP->setCleanup(IsCleanup); for (unsigned J = 0; J != NumClauses; ++J) { LandingPadInst::ClauseType CT = LandingPadInst::ClauseType(Record[Idx++]); (void)CT; Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) { delete LP; return error("Invalid record"); } IGC_ASSERT((CT != LandingPadInst::Catch || !isa(Val->getType())) && "Catch clause has a invalid type!"); IGC_ASSERT((CT != LandingPadInst::Filter || isa(Val->getType())) && "Filter clause has invalid type!"); LP->addClause(cast(Val)); } I = LP; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align] if (Record.size() != 4) return error("Invalid record"); uint64_t AlignRecord = Record[3]; const uint64_t InAllocaMask = uint64_t(1) << 5; const uint64_t ExplicitTypeMask = uint64_t(1) << 6; const uint64_t SwiftErrorMask = uint64_t(1) << 7; const uint64_t FlagMask = InAllocaMask | ExplicitTypeMask | SwiftErrorMask; bool InAlloca = AlignRecord & InAllocaMask; bool SwiftError = AlignRecord & SwiftErrorMask; FullTy = getFullyStructuredTypeByID(Record[0]); Type *Ty = flattenPointerTypes(FullTy); if ((AlignRecord & ExplicitTypeMask) == 0) { auto *PTy = dyn_cast_or_null(Ty); if (!PTy) return error("Old-style alloca with a non-pointer type"); std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); } Type *OpTy = getTypeByID(Record[1]); Value *Size = getFnValueByID(Record[2], OpTy); MaybeAlign Align; if (Error Err = parseAlignmentValue(AlignRecord & ~FlagMask, Align)) { return Err; } if (!Ty || !Size) return error("Invalid record"); // FIXME: Make this an optional field. const DataLayout &DL = TheModule->getDataLayout(); unsigned AS = DL.getAllocaAddrSpace(); AllocaInst *AI = new AllocaInst(Ty, AS, Size, Align); AI->setUsedWithInAlloca(InAlloca); AI->setSwiftError(SwiftError); I = AI; FullTy = PointerType::get(FullTy, AS); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy) || (OpNum + 2 != Record.size() && OpNum + 3 != Record.size())) return error("Invalid record"); if (!isa(Op->getType())) return error("Load operand is not a pointer type"); Type *Ty = nullptr; if (OpNum + 3 == Record.size()) { FullTy = getFullyStructuredTypeByID(Record[OpNum++]); Ty = flattenPointerTypes(FullTy); } else std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; MaybeAlign Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Ty, Op, "", Record[OpNum + 1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOADATOMIC: { // LOADATOMIC: [opty, op, align, vol, ordering, ssid] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy) || (OpNum + 4 != Record.size() && OpNum + 5 != Record.size())) return error("Invalid record"); if (!isa(Op->getType())) return error("Load operand is not a pointer type"); Type *Ty = nullptr; if (OpNum + 5 == Record.size()) { FullTy = getFullyStructuredTypeByID(Record[OpNum++]); Ty = flattenPointerTypes(FullTy); } else std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Release || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); MaybeAlign Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Ty, Op, "", Record[OpNum + 1], Align, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STORE: case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol] unsigned OpNum = 0; Value *Val, *Ptr; Type *FullTy; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy) || (BitCode == bitc::FUNC_CODE_INST_STORE ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, getPointerElementFlatType(FullTy), Val)) || OpNum + 2 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; MaybeAlign Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum + 1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STOREATOMIC: case bitc::FUNC_CODE_INST_STOREATOMIC_OLD: { // STOREATOMIC: [ptrty, ptr, val, align, vol, ordering, ssid] unsigned OpNum = 0; Value *Val, *Ptr; Type *FullTy; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy) || !isa(Ptr->getType()) || (BitCode == bitc::FUNC_CODE_INST_STOREATOMIC ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, getPointerElementFlatType(FullTy), Val)) || OpNum + 4 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Acquire || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); MaybeAlign Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum + 1], Align, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMPXCHG_OLD: case bitc::FUNC_CODE_INST_CMPXCHG: { // CMPXCHG:[ptrty, ptr, cmp, new, vol, successordering, ssid, // failureordering?, isweak?] unsigned OpNum = 0; Value *Ptr, *Cmp, *New; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy)) return error("Invalid record"); if (!isa(Ptr->getType())) return error("Cmpxchg operand is not a pointer type"); if (BitCode == bitc::FUNC_CODE_INST_CMPXCHG) { if (getValueTypePair(Record, OpNum, NextValueNo, Cmp, &FullTy)) return error("Invalid record"); } else if (popValue(Record, OpNum, NextValueNo, getPointerElementFlatType(FullTy), Cmp)) return error("Invalid record"); else FullTy = cast(FullTy)->getElementType(); if (popValue(Record, OpNum, NextValueNo, Cmp->getType(), New) || Record.size() < OpNum + 3 || Record.size() > OpNum + 5) return error("Invalid record"); AtomicOrdering SuccessOrdering = getDecodedOrdering(Record[OpNum + 1]); if (SuccessOrdering == AtomicOrdering::NotAtomic || SuccessOrdering == AtomicOrdering::Unordered) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 2]); if (Error Err = typeCheckLoadStoreInst(Cmp->getType(), Ptr->getType())) return Err; AtomicOrdering FailureOrdering; if (Record.size() < 7) FailureOrdering = AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrdering); else FailureOrdering = getDecodedOrdering(Record[OpNum + 3]); I = new AtomicCmpXchgInst(Ptr, Cmp, New, SuccessOrdering, FailureOrdering, SSID); FullTy = StructType::get(Context, {FullTy, Type::getInt1Ty(Context)}); cast(I)->setVolatile(Record[OpNum]); if (Record.size() < 8) { // Before weak cmpxchgs existed, the instruction simply returned the // value loaded from memory, so bitcode files from that era will be // expecting the first component of a modern cmpxchg. CurBB->getInstList().push_back(I); I = ExtractValueInst::Create(I, 0); FullTy = cast(FullTy)->getElementType(0); } else { cast(I)->setWeak(Record[OpNum+4]); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ATOMICRMW: { // ATOMICRMW:[ptrty, ptr, val, op, vol, ordering, ssid] unsigned OpNum = 0; Value *Ptr, *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy) || !isa(Ptr->getType()) || popValue(Record, OpNum, NextValueNo, getPointerElementFlatType(FullTy), Val) || OpNum + 4 != Record.size()) return error("Invalid record"); AtomicRMWInst::BinOp Operation = getDecodedRMWOperation(Record[OpNum]); if (Operation < AtomicRMWInst::FIRST_BINOP || Operation > AtomicRMWInst::LAST_BINOP) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); I = new AtomicRMWInst(Operation, Ptr, Val, Ordering, SSID); FullTy = getPointerElementFlatType(FullTy); cast(I)->setVolatile(Record[OpNum+1]); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_FENCE: { // FENCE:[ordering, ssid] if (2 != Record.size()) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[0]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered || Ordering == AtomicOrdering::Monotonic) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[1]); I = new FenceInst(Context, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CALL: { // CALL: [paramattrs, cc, fmf, fnty, fnid, arg0, arg1...] if (Record.size() < 3) return error("Invalid record"); unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; FastMathFlags FMF; if ((CCInfo >> bitc::CALL_FMF) & 1) { FMF = getDecodedFastMathFlags(Record[OpNum++]); if (!FMF.any()) return error("Fast math flags indicator set for call with no FMF"); } FunctionType *FTy = nullptr; FunctionType *FullFTy = nullptr; if ((CCInfo >> bitc::CALL_EXPLICIT_TYPE) & 1) { FullFTy = dyn_cast(getFullyStructuredTypeByID(Record[OpNum++])); if (!FullFTy) return error("Explicit call type is not a function type"); FTy = cast(flattenPointerTypes(FullFTy)); } Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee, &FullTy)) return error("Invalid record"); PointerType *OpTy = dyn_cast(Callee->getType()); if (!OpTy) return error("Callee is not a pointer type"); if (!FTy) { FullFTy = dyn_cast(cast(FullTy)->getElementType()); if (!FullFTy) return error("Callee is not of pointer to function type"); FTy = cast(flattenPointerTypes(FullFTy)); } else if (getPointerElementFlatType(FullTy) != FTy) return error("Explicit call type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Args; SmallVector ArgsFullTys; // Read the fixed params. for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { if (FTy->getParamType(i)->isLabelTy()) Args.push_back(getBasicBlock(Record[OpNum])); else Args.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); ArgsFullTys.push_back(FullFTy->getParamType(i)); if (!Args.back()) return error("Invalid record"); } // Read type/value pairs for varargs params. if (!FTy->isVarArg()) { if (OpNum != Record.size()) return error("Invalid record"); } else { while (OpNum != Record.size()) { Value *Op; Type *FullTy; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy)) return error("Invalid record"); Args.push_back(Op); ArgsFullTys.push_back(FullTy); } } I = CallInst::Create(FTy, Callee, Args, OperandBundles); FullTy = FullFTy->getReturnType(); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast((0x7ff & CCInfo) >> bitc::CALL_CCONV)); CallInst::TailCallKind TCK = CallInst::TCK_None; if (CCInfo & 1 << bitc::CALL_TAIL) TCK = CallInst::TCK_Tail; if (CCInfo & (1 << bitc::CALL_MUSTTAIL)) TCK = CallInst::TCK_MustTail; if (CCInfo & (1 << bitc::CALL_NOTAIL)) TCK = CallInst::TCK_NoTail; cast(I)->setTailCallKind(TCK); cast(I)->setAttributes(PAL); propagateByValTypes(cast(I), ArgsFullTys); if (FMF.any()) { if (!isa(I)) return error("Fast-math-flags specified for call without " "floating-point scalar or vector return type"); I->setFastMathFlags(FMF); } break; } case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty] if (Record.size() < 3) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Op = getValue(Record, 1, NextValueNo, OpTy); FullTy = getFullyStructuredTypeByID(Record[2]); Type *ResTy = flattenPointerTypes(FullTy); if (!OpTy || !Op || !ResTy) return error("Invalid record"); I = new VAArgInst(Op, ResTy); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_OPERAND_BUNDLE: { // A call or an invoke can be optionally prefixed with some variable // number of operand bundle blocks. These blocks are read into // OperandBundles and consumed at the next call or invoke instruction. if (Record.size() < 1 || Record[0] >= BundleTags.size()) return error("Invalid record"); std::vector Inputs; unsigned OpNum = 1; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Inputs.push_back(Op); } OperandBundles.emplace_back(BundleTags[Record[0]], std::move(Inputs)); continue; } case bitc::FUNC_CODE_INST_FREEZE: { // FREEZE: [opty,opval] unsigned OpNum = 0; Value *Op = nullptr; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy)) return error("Invalid record"); if (OpNum != Record.size()) return error("Invalid record"); I = new FreezeInst(Op); InstructionList.push_back(I); break; } } // Add instruction to end of current BB. If there is no current BB, reject // this file. if (!CurBB) { I->deleteValue(); return error("Invalid instruction with no BB"); } if (!OperandBundles.empty()) { I->deleteValue(); return error("Operand bundles found with no consumer"); } CurBB->getInstList().push_back(I); // If this was a terminator instruction, move to the next block. if (I->isTerminator()) { ++CurBBNo; CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr; } // Non-void values get registered in the value table for future use. if (!I->getType()->isVoidTy()) { if (!FullTy) { FullTy = I->getType(); IGC_ASSERT( !FullTy->isPointerTy() && !isa(FullTy) && !isa(FullTy) && (!isa(FullTy) || FullTy->getVectorElementType()->isFloatingPointTy() || FullTy->getVectorElementType()->isIntegerTy()) && "Structured types must be assigned with corresponding non-opaque " "pointer type"); } IGC_ASSERT(I->getType() == flattenPointerTypes(FullTy) && "Incorrect fully structured type provided for Instruction"); ValueList.assignValue(I, NextValueNo++, FullTy); } } OutOfRecordLoop: if (!OperandBundles.empty()) return error("Operand bundles found with no consumer"); // Check the function list for unresolved values. if (Argument *A = dyn_cast(ValueList.back())) { if (!A->getParent()) { // We found at least one unresolved value. Nuke them all to avoid leaks. for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){ if ((A = dyn_cast_or_null(ValueList[i])) && !A->getParent()) { A->replaceAllUsesWith(UndefValue::get(A->getType())); delete A; } } return error("Never resolved value found in function"); } } // Unexpected unresolved metadata about to be dropped. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: outgoing forward refs"); // Trim the value list down to the size it was before we parsed this function. ValueList.shrinkTo(ModuleValueListSize); MDLoader->shrinkTo(ModuleMDLoaderSize); std::vector().swap(FunctionBBs); return Error::success(); } /// Find the function body in the bitcode stream Error BitcodeReader::findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator) { while (DeferredFunctionInfoIterator->second == 0) { // This is the fallback handling for the old format bitcode that // didn't contain the function index in the VST, or when we have // an anonymous function which would not have a VST entry. // Assert that we have one of those two cases. IGC_ASSERT(VSTOffset == 0 || !F->hasName()); // Parse the next body in the stream and set its position in the // DeferredFunctionInfo map. if (Error Err = rememberAndSkipFunctionBodies()) return Err; } return Error::success(); } SyncScope::ID BitcodeReader::getDecodedSyncScopeID(unsigned Val) { if (Val == SyncScope::SingleThread || Val == SyncScope::System) return SyncScope::ID(Val); if (Val >= SSIDs.size()) return SyncScope::System; // Map unknown synchronization scopes to system. return SSIDs[Val]; } //===----------------------------------------------------------------------===// // GVMaterializer implementation //===----------------------------------------------------------------------===// Error BitcodeReader::materialize(GlobalValue *GV) { Function *F = dyn_cast(GV); // If it's not a function or is already material, ignore the request. if (!F || !F->isMaterializable()) return Error::success(); DenseMap::iterator DFII = DeferredFunctionInfo.find(F); IGC_ASSERT(DFII != DeferredFunctionInfo.end() && "Deferred function not found!"); // If its position is recorded as 0, its body is somewhere in the stream // but we haven't seen it yet. if (DFII->second == 0) if (Error Err = findFunctionInStream(F, DFII)) return Err; // Materialize metadata before parsing any function bodies. if (Error Err = materializeMetadata()) return Err; // Move the bit stream to the saved position of the deferred function body. if (Error JumpFailed = Stream.JumpToBit(DFII->second)) return JumpFailed; if (Error Err = parseFunctionBody(F)) return Err; F->setIsMaterializable(false); if (StripDebugInfo) stripDebugInfo(*F); // Upgrade any old intrinsic calls in the function. for (auto &I : UpgradedIntrinsics) { for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) { User *U = *UI; ++UI; if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } } // Update calls to the remangled intrinsics for (auto &I : RemangledIntrinsics) for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) // Don't expect any other users than call sites CallSite(*UI++).setCalledFunction(I.second); // Finish fn->subprogram upgrade for materialized functions. if (DISubprogram *SP = MDLoader->lookupSubprogramForFunction(F)) F->setSubprogram(SP); // Check if the TBAA Metadata are valid, otherwise we will need to strip them. if (!MDLoader->isStrippingTBAA()) { for (auto &I : instructions(F)) { MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa); if (!TBAA || TBAAVerifyHelper.visitTBAAMetadata(I, TBAA)) continue; MDLoader->setStripTBAA(true); stripTBAA(F->getParent()); } } // Bring in any functions that this function forward-referenced via // blockaddresses. return materializeForwardReferencedFunctions(); } Error BitcodeReader::materializeModule() { if (Error Err = materializeMetadata()) return Err; // Promise to materialize all forward references. WillMaterializeAllForwardRefs = true; // Iterate over the module, deserializing any functions that are still on // disk. for (Function &F : *TheModule) { if (Error Err = materialize(&F)) return Err; } // At this point, if there are any function bodies, parse the rest of // the bits in the module past the last function block we have recorded // through either lazy scanning or the VST. if (LastFunctionBlockBit || NextUnreadBit) if (Error Err = parseModule(LastFunctionBlockBit > NextUnreadBit ? LastFunctionBlockBit : NextUnreadBit)) return Err; // Check that all block address forward references got resolved (as we // promised above). if (!BasicBlockFwdRefs.empty()) return error("Never resolved function from blockaddress"); // Upgrade any intrinsic calls that slipped through (should not happen!) and // delete the old functions to clean up. We can't do this unless the entire // module is materialized because there could always be another function body // with calls to the old function. for (auto &I : UpgradedIntrinsics) { for (auto *U : I.first->users()) { if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } if (!I.first->use_empty()) I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } UpgradedIntrinsics.clear(); // Do the same for remangled intrinsics for (auto &I : RemangledIntrinsics) { I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } RemangledIntrinsics.clear(); UpgradeDebugInfo(*TheModule); UpgradeModuleFlags(*TheModule); UpgradeARCRuntime(*TheModule); return Error::success(); } std::vector BitcodeReader::getIdentifiedStructTypes() const { return IdentifiedStructTypes; } ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader( BitstreamCursor Cursor, StringRef Strtab, ModuleSummaryIndex &TheIndex, StringRef ModulePath, unsigned ModuleId) : BitcodeReaderBase(std::move(Cursor), Strtab), TheIndex(TheIndex), ModulePath(ModulePath), ModuleId(ModuleId) {} void ModuleSummaryIndexBitcodeReader::addThisModule() { TheIndex.addModule(ModulePath, ModuleId); } ModuleSummaryIndex::ModuleInfo * ModuleSummaryIndexBitcodeReader::getThisModule() { return TheIndex.getModule(ModulePath); } std::pair ModuleSummaryIndexBitcodeReader::getValueInfoFromValueId(unsigned ValueId) { auto VGI = ValueIdToValueInfoMap[ValueId]; IGC_ASSERT(VGI.first); return VGI; } void ModuleSummaryIndexBitcodeReader::setValueGUID( uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage, StringRef SourceFileName) { std::string GlobalId = GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName); auto ValueGUID = GlobalValue::getGUID(GlobalId); auto OriginalNameID = ValueGUID; if (GlobalValue::isLocalLinkage(Linkage)) OriginalNameID = GlobalValue::getGUID(ValueName); // UseStrtab is false for legacy summary formats and value names are // created on stack. In that case we save the name in a string saver in // the index so that the value name can be recorded. ValueIdToValueInfoMap[ValueID] = std::make_pair( TheIndex.getOrInsertValueInfo( ValueGUID, UseStrtab ? ValueName : TheIndex.saveString(ValueName)), OriginalNameID); } // Specialized value symbol table parser used when reading module index // blocks where we don't actually create global values. The parsed information // is saved in the bitcode reader for use when later parsing summaries. Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap) { // With a strtab the VST is not required to parse the summary. if (UseStrtab) return Error::success(); IGC_ASSERT(Offset > 0 && "Expected non-zero VST offset"); Expected MaybeCurrentBit = jumpToValueSymbolTable(Offset, Stream); if (!MaybeCurrentBit) return MaybeCurrentBit.takeError(); uint64_t CurrentBit = MaybeCurrentBit.get(); if (Error Err = Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return Err; SmallVector Record; // Read all the records for this value table. SmallString<128> ValueName; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // Done parsing VST, jump back to wherever we came from. if (Error JumpFailed = Stream.JumpToBit(CurrentBit)) return JumpFailed; return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore (e.g. VST_CODE_BBENTRY records). break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] if (convertToString(Record, 1, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; setValueGUID(ValueID, ValueName, Linkage, SourceFileName); ValueName.clear(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] if (convertToString(Record, 2, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; setValueGUID(ValueID, ValueName, Linkage, SourceFileName); ValueName.clear(); break; } case bitc::VST_CODE_COMBINED_ENTRY: { // VST_CODE_COMBINED_ENTRY: [valueid, refguid] unsigned ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; // The "original name", which is the second value of the pair will be // overriden later by a FS_COMBINED_ORIGINAL_NAME in the combined index. ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(RefGUID), RefGUID); break; } } } } // Parse just the blocks needed for building the index out of the module. // At the end of this routine the module Index is populated with a map // from global value id to GlobalValueSummary objects. Error ModuleSummaryIndexBitcodeReader::parseModule() { if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return Err; SmallVector Record; DenseMap ValueIdToLinkageMap; unsigned ValueId = 0; // Read the index for this module. while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Error Err = Stream.SkipBlock()) return Err; break; case bitc::BLOCKINFO_BLOCK_ID: // Need to parse these to get abbrev ids (e.g. for VST) if (readBlockInfo()) return error("Malformed block"); break; case bitc::VALUE_SYMTAB_BLOCK_ID: // Should have been parsed earlier via VSTOffset, unless there // is no summary section. IGC_ASSERT(((SeenValueSymbolTable && VSTOffset > 0) || !SeenGlobalValSummary) && "Expected early VST parse via VSTOffset record"); if (Error Err = Stream.SkipBlock()) return Err; break; case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID: // Add the module if it is a per-module index (has a source file name). if (!SourceFileName.empty()) addThisModule(); IGC_ASSERT(!SeenValueSymbolTable && "Already read VST when parsing summary block?"); // We might not have a VST if there were no values in the // summary. An empty summary block generated when we are // performing ThinLTO compiles so we don't later invoke // the regular LTO process on them. if (VSTOffset > 0) { if (Error Err = parseValueSymbolTable(VSTOffset, ValueIdToLinkageMap)) return Err; SeenValueSymbolTable = true; } SeenGlobalValSummary = true; if (Error Err = parseEntireSummary(Entry.ID)) return Err; break; case bitc::MODULE_STRTAB_BLOCK_ID: if (Error Err = parseModuleStringTable()) return Err; break; } continue; case BitstreamEntry::Record: { Record.clear(); Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (MaybeBitCode.get()) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { if (Error Err = parseVersionRecord(Record).takeError()) return Err; break; } /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: { SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); SourceFileName = ValueName.c_str(); break; } /// MODULE_CODE_HASH: [5*i32] case bitc::MODULE_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); auto &Hash = getThisModule()->second.second; int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); Hash[Pos++] = Val; } break; } /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one // word before the start of the identification or module block, which // was historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; // v1 GLOBALVAR: [pointer type, isconst, initid, linkage, ...] // v1 FUNCTION: [type, callingconv, isproto, linkage, ...] // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, ...] // v2: [strtab offset, strtab size, v1] case bitc::MODULE_CODE_GLOBALVAR: case bitc::MODULE_CODE_FUNCTION: case bitc::MODULE_CODE_ALIAS: { StringRef Name; ArrayRef GVRecord; std::tie(Name, GVRecord) = readNameFromStrtab(Record); if (GVRecord.size() <= 3) return error("Invalid record"); uint64_t RawLinkage = GVRecord[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); if (!UseStrtab) { ValueIdToLinkageMap[ValueId++] = Linkage; break; } setValueGUID(ValueId++, Name, Linkage, SourceFileName); break; } } } continue; } } } std::vector ModuleSummaryIndexBitcodeReader::makeRefList(ArrayRef Record) { std::vector Ret; Ret.reserve(Record.size()); for (uint64_t RefValueId : Record) Ret.push_back(getValueInfoFromValueId(RefValueId).first); return Ret; } std::vector ModuleSummaryIndexBitcodeReader::makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile, bool HasRelBF) { std::vector Ret; Ret.reserve(Record.size()); for (unsigned I = 0, E = Record.size(); I != E; ++I) { CalleeInfo::HotnessType Hotness = CalleeInfo::HotnessType::Unknown; uint64_t RelBF = 0; ValueInfo Callee = getValueInfoFromValueId(Record[I]).first; if (IsOldProfileFormat) { I += 1; // Skip old callsitecount field if (HasProfile) I += 1; // Skip old profilecount field } else if (HasProfile) Hotness = static_cast(Record[++I]); else if (HasRelBF) RelBF = Record[++I]; Ret.push_back(FunctionSummary::EdgeTy{Callee, CalleeInfo(Hotness, RelBF)}); } return Ret; } static void parseWholeProgramDevirtResolutionByArg(ArrayRef Record, size_t &Slot, WholeProgramDevirtResolution &Wpd) { uint64_t ArgNum = Record[Slot++]; WholeProgramDevirtResolution::ByArg &B = Wpd.ResByArg[{Record.begin() + Slot, Record.begin() + Slot + ArgNum}]; Slot += (size_t)ArgNum; B.TheKind = static_cast(Record[Slot++]); B.Info = Record[Slot++]; B.Byte = Record[Slot++]; B.Bit = Record[Slot++]; } static void parseWholeProgramDevirtResolution(ArrayRef Record, StringRef Strtab, size_t &Slot, TypeIdSummary &TypeId) { uint64_t Id = Record[Slot++]; WholeProgramDevirtResolution &Wpd = TypeId.WPDRes[Id]; Wpd.TheKind = static_cast(Record[Slot++]); Wpd.SingleImplName = {Strtab.data() + Record[Slot], static_cast(Record[Slot + 1])}; Slot += 2; uint64_t ResByArgNum = Record[Slot++]; for (uint64_t I = 0; I != ResByArgNum; ++I) parseWholeProgramDevirtResolutionByArg(Record, Slot, Wpd); } static void parseTypeIdSummaryRecord(ArrayRef Record, StringRef Strtab, ModuleSummaryIndex &TheIndex) { size_t Slot = 0; TypeIdSummary &TypeId = TheIndex.getOrInsertTypeIdSummary( {Strtab.data() + Record[Slot], static_cast(Record[Slot + 1])}); Slot += 2; TypeId.TTRes.TheKind = static_cast(Record[Slot++]); TypeId.TTRes.SizeM1BitWidth = Record[Slot++]; TypeId.TTRes.AlignLog2 = Record[Slot++]; TypeId.TTRes.SizeM1 = Record[Slot++]; TypeId.TTRes.BitMask = Record[Slot++]; TypeId.TTRes.InlineBits = Record[Slot++]; while (Slot < Record.size()) parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId); } void ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableInfo( ArrayRef Record, size_t &Slot, TypeIdCompatibleVtableInfo &TypeId) { uint64_t Offset = Record[Slot++]; ValueInfo Callee = getValueInfoFromValueId(Record[Slot++]).first; TypeId.push_back({Offset, Callee}); } void ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableSummaryRecord( ArrayRef Record) { size_t Slot = 0; TypeIdCompatibleVtableInfo &TypeId = TheIndex.getOrInsertTypeIdCompatibleVtableSummary( {Strtab.data() + Record[Slot], static_cast(Record[Slot + 1])}); Slot += 2; while (Slot < Record.size()) parseTypeIdCompatibleVtableInfo(Record, Slot, TypeId); } static void setSpecialRefs(std::vector &Refs, unsigned ROCnt, unsigned WOCnt) { // Readonly and writeonly refs are in the end of the refs list. IGC_ASSERT(ROCnt + WOCnt <= Refs.size()); unsigned FirstWORef = Refs.size() - WOCnt; unsigned RefNo = FirstWORef - ROCnt; for (; RefNo < FirstWORef; ++RefNo) Refs[RefNo].setReadOnly(); for (; RefNo < Refs.size(); ++RefNo) Refs[RefNo].setWriteOnly(); } // Eagerly parse the entire summary block. This populates the GlobalValueSummary // objects in the index. Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { if (Error Err = Stream.EnterSubBlock(ID)) return Err; SmallVector Record; // Parse version { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); if (Entry.Kind != BitstreamEntry::Record) return error("Invalid Summary Block: record for version expected"); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); if (MaybeRecord.get() != bitc::FS_VERSION) return error("Invalid Summary Block: version expected"); } const uint64_t Version = Record[0]; const bool IsOldProfileFormat = Version == 1; if (Version < 1 || Version > //ModuleSummaryIndex::BitcodeSummaryVersion 8) return error("Invalid summary version " + Twine(Version) + ". Version should be in the range [1-" + Twine( //ModuleSummaryIndex::BitcodeSummaryVersion 8) + "]."); Record.clear(); // Keep around the last seen summary to be used when we see an optional // "OriginalName" attachement. GlobalValueSummary *LastSeenSummary = nullptr; GlobalValue::GUID LastSeenGUID = 0; // We can expect to see any number of type ID information records before // each function summary records; these variables store the information // collected so far so that it can be used to create the summary object. std::vector PendingTypeTests; std::vector PendingTypeTestAssumeVCalls, PendingTypeCheckedLoadVCalls; std::vector PendingTypeTestAssumeConstVCalls, PendingTypeCheckedLoadConstVCalls; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. The record format depends on whether this // is a per-module index or a combined index file. In the per-module // case the records contain the associated value's ID for correlation // with VST entries. In the combined index the correlation is done // via the bitcode offset of the summary records (which were saved // in the combined index VST entries). The records also contain // information used for ThinLTO renaming and importing. Record.clear(); Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (unsigned BitCode = MaybeBitCode.get()) { default: // Default behavior: ignore. break; case bitc::FS_FLAGS: { // [flags] uint64_t Flags = Record[0]; // Scan flags. IGC_ASSERT(Flags <= 0x3f && "Unexpected bits in flag"); // 1 bit: WithGlobalValueDeadStripping flag. // Set on combined index only. if (Flags & 0x1) TheIndex.setWithGlobalValueDeadStripping(); // 1 bit: SkipModuleByDistributedBackend flag. // Set on combined index only. if (Flags & 0x2) TheIndex.setSkipModuleByDistributedBackend(); // 1 bit: HasSyntheticEntryCounts flag. // Set on combined index only. if (Flags & 0x4) TheIndex.setHasSyntheticEntryCounts(); // 1 bit: DisableSplitLTOUnit flag. // Set on per module indexes. It is up to the client to validate // the consistency of this flag across modules being linked. if (Flags & 0x8) TheIndex.setEnableSplitLTOUnit(); // 1 bit: PartiallySplitLTOUnits flag. // Set on combined index only. if (Flags & 0x10) TheIndex.setPartiallySplitLTOUnits(); // 1 bit: WithAttributePropagation flag. // Set on combined index only. if (Flags & 0x20) TheIndex.setWithAttributePropagation(); break; } case bitc::FS_VALUE_GUID: { // [valueid, refguid] uint64_t ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(RefGUID), RefGUID); break; } // FS_PERMODULE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_PERMODULE_PROFILE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, // n x (valueid, hotness)] // FS_PERMODULE_RELBF: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, // n x (valueid, relblockfreq)] case bitc::FS_PERMODULE: case bitc::FS_PERMODULE_RELBF: case bitc::FS_PERMODULE_PROFILE: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned InstCount = Record[2]; uint64_t RawFunFlags = 0; unsigned NumRefs = Record[3]; unsigned NumRORefs = 0, NumWORefs = 0; int RefListStartIndex = 4; if (Version >= 4) { RawFunFlags = Record[3]; NumRefs = Record[4]; RefListStartIndex = 5; if (Version >= 5) { NumRORefs = Record[5]; RefListStartIndex = 6; if (Version >= 7) { NumWORefs = Record[6]; RefListStartIndex = 7; } } } auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_PERMODULE_PROFILE); bool HasRelBF = (BitCode == bitc::FS_PERMODULE_RELBF); std::vector Calls = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile, HasRelBF); setSpecialRefs(Refs, NumRORefs, NumWORefs); auto FS = std::make_unique( Flags, InstCount, getDecodedFFlags(RawFunFlags), /*EntryCount=*/0, std::move(Refs), std::move(Calls), std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeCheckedLoadConstVCalls)); auto VIAndOriginalGUID = getValueInfoFromValueId(ValueID); FS->setModulePath(getThisModule()->first()); FS->setOriginalName(VIAndOriginalGUID.second); TheIndex.addGlobalValueSummary(VIAndOriginalGUID.first, std::move(FS)); break; } // FS_ALIAS: [valueid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_PERMODULE entries, as // they expect all aliasee summaries to be available. case bitc::FS_ALIAS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned AliaseeID = Record[2]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = std::make_unique(Flags); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. AS->setModulePath(getThisModule()->first()); auto AliaseeVI = getValueInfoFromValueId(AliaseeID).first; auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeVI, ModulePath); if (!AliaseeInModule) return error("Alias expects aliasee summary to be parsed"); AS->setAliasee(AliaseeVI, AliaseeInModule); auto GUID = getValueInfoFromValueId(ValueID); AS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(AS)); break; } // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags, n x valueid] case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned RefArrayStart = 2; GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false, /* WriteOnly */ false); auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[2]); RefArrayStart = 3; } std::vector Refs = makeRefList(ArrayRef(Record).slice(RefArrayStart)); auto FS = std::make_unique(Flags, GVF, std::move(Refs)); FS->setModulePath(getThisModule()->first()); auto GUID = getValueInfoFromValueId(ValueID); FS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(FS)); break; } // FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags, // numrefs, numrefs x valueid, // n x (valueid, offset)] case bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; GlobalVarSummary::GVarFlags GVF = getDecodedGVarFlags(Record[2]); unsigned NumRefs = Record[3]; unsigned RefListStartIndex = 4; unsigned VTableListStartIndex = RefListStartIndex + NumRefs; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); VTableFuncList VTableFuncs; for (unsigned I = VTableListStartIndex, E = Record.size(); I != E; ++I) { ValueInfo Callee = getValueInfoFromValueId(Record[I]).first; uint64_t Offset = Record[++I]; VTableFuncs.push_back({Callee, Offset}); } auto VS = std::make_unique(Flags, GVF, std::move(Refs)); VS->setModulePath(getThisModule()->first()); VS->setVTableFuncs(VTableFuncs); auto GUID = getValueInfoFromValueId(ValueID); VS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(VS)); break; } // FS_COMBINED: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid, hotness)] case bitc::FS_COMBINED: case bitc::FS_COMBINED_PROFILE: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned InstCount = Record[3]; uint64_t RawFunFlags = 0; uint64_t EntryCount = 0; unsigned NumRefs = Record[4]; unsigned NumRORefs = 0, NumWORefs = 0; int RefListStartIndex = 5; if (Version >= 4) { RawFunFlags = Record[4]; RefListStartIndex = 6; size_t NumRefsIndex = 5; if (Version >= 5) { unsigned NumRORefsOffset = 1; RefListStartIndex = 7; if (Version >= 6) { NumRefsIndex = 6; EntryCount = Record[5]; RefListStartIndex = 8; if (Version >= 7) { RefListStartIndex = 9; NumWORefs = Record[8]; NumRORefsOffset = 2; } } NumRORefs = Record[RefListStartIndex - NumRORefsOffset]; } NumRefs = Record[NumRefsIndex]; } auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_COMBINED_PROFILE); std::vector Edges = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile, false); ValueInfo VI = getValueInfoFromValueId(ValueID).first; setSpecialRefs(Refs, NumRORefs, NumWORefs); auto FS = std::make_unique( Flags, InstCount, getDecodedFFlags(RawFunFlags), EntryCount, std::move(Refs), std::move(Edges), std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeCheckedLoadConstVCalls)); LastSeenSummary = FS.get(); LastSeenGUID = VI.getGUID(); FS->setModulePath(ModuleIdMap[ModuleId]); TheIndex.addGlobalValueSummary(VI, std::move(FS)); break; } // FS_COMBINED_ALIAS: [valueid, modid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_COMBINED entries, as // they expect all aliasee summaries to be available. case bitc::FS_COMBINED_ALIAS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned AliaseeValueId = Record[3]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = std::make_unique(Flags); LastSeenSummary = AS.get(); AS->setModulePath(ModuleIdMap[ModuleId]); auto AliaseeVI = getValueInfoFromValueId(AliaseeValueId).first; auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeVI, AS->modulePath()); AS->setAliasee(AliaseeVI, AliaseeInModule); ValueInfo VI = getValueInfoFromValueId(ValueID).first; LastSeenGUID = VI.getGUID(); TheIndex.addGlobalValueSummary(VI, std::move(AS)); break; } // FS_COMBINED_GLOBALVAR_INIT_REFS: [valueid, modid, flags, n x valueid] case bitc::FS_COMBINED_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned RefArrayStart = 3; GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false, /* WriteOnly */ false); auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[3]); RefArrayStart = 4; } std::vector Refs = makeRefList(ArrayRef(Record).slice(RefArrayStart)); auto FS = std::make_unique(Flags, GVF, std::move(Refs)); LastSeenSummary = FS.get(); FS->setModulePath(ModuleIdMap[ModuleId]); ValueInfo VI = getValueInfoFromValueId(ValueID).first; LastSeenGUID = VI.getGUID(); TheIndex.addGlobalValueSummary(VI, std::move(FS)); break; } // FS_COMBINED_ORIGINAL_NAME: [original_name] case bitc::FS_COMBINED_ORIGINAL_NAME: { uint64_t OriginalName = Record[0]; if (!LastSeenSummary) return error("Name attachment that does not follow a combined record"); LastSeenSummary->setOriginalName(OriginalName); TheIndex.addOriginalName(LastSeenGUID, OriginalName); // Reset the LastSeenSummary LastSeenSummary = nullptr; LastSeenGUID = 0; break; } case bitc::FS_TYPE_TESTS: IGC_ASSERT(PendingTypeTests.empty()); PendingTypeTests.insert(PendingTypeTests.end(), Record.begin(), Record.end()); break; case bitc::FS_TYPE_TEST_ASSUME_VCALLS: IGC_ASSERT(PendingTypeTestAssumeVCalls.empty()); for (unsigned I = 0; I != Record.size(); I += 2) PendingTypeTestAssumeVCalls.push_back({Record[I], Record[I+1]}); break; case bitc::FS_TYPE_CHECKED_LOAD_VCALLS: IGC_ASSERT(PendingTypeCheckedLoadVCalls.empty()); for (unsigned I = 0; I != Record.size(); I += 2) PendingTypeCheckedLoadVCalls.push_back({Record[I], Record[I+1]}); break; case bitc::FS_TYPE_TEST_ASSUME_CONST_VCALL: PendingTypeTestAssumeConstVCalls.push_back( {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; case bitc::FS_TYPE_CHECKED_LOAD_CONST_VCALL: PendingTypeCheckedLoadConstVCalls.push_back( {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; case bitc::FS_CFI_FUNCTION_DEFS: { std::set &CfiFunctionDefs = TheIndex.cfiFunctionDefs(); for (unsigned I = 0; I != Record.size(); I += 2) CfiFunctionDefs.insert( {Strtab.data() + Record[I], static_cast(Record[I + 1])}); break; } case bitc::FS_CFI_FUNCTION_DECLS: { std::set &CfiFunctionDecls = TheIndex.cfiFunctionDecls(); for (unsigned I = 0; I != Record.size(); I += 2) CfiFunctionDecls.insert( {Strtab.data() + Record[I], static_cast(Record[I + 1])}); break; } case bitc::FS_TYPE_ID: parseTypeIdSummaryRecord(Record, Strtab, TheIndex); break; case bitc::FS_TYPE_ID_METADATA: parseTypeIdCompatibleVtableSummaryRecord(Record); break; } } llvm_unreachable("Exit infinite loop"); } // Parse the module string table block into the Index. // This populates the ModulePathStringTable map in the index. Error ModuleSummaryIndexBitcodeReader::parseModuleStringTable() { if (Error Err = Stream.EnterSubBlock(bitc::MODULE_STRTAB_BLOCK_ID)) return Err; SmallVector Record; SmallString<128> ModulePath; ModuleSummaryIndex::ModuleInfo *LastSeenModule = nullptr; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; case bitc::MST_CODE_ENTRY: { // MST_ENTRY: [modid, namechar x N] uint64_t ModuleId = Record[0]; if (convertToString(Record, 1, ModulePath)) return error("Invalid record"); LastSeenModule = TheIndex.addModule(ModulePath, ModuleId); ModuleIdMap[ModuleId] = LastSeenModule->first(); ModulePath.clear(); break; } /// MST_CODE_HASH: [5*i32] case bitc::MST_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); if (!LastSeenModule) return error("Invalid hash that does not follow a module path"); int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); LastSeenModule->second.second[Pos++] = Val; } // Reset LastSeenModule to avoid overriding the hash unexpectedly. LastSeenModule = nullptr; break; } } } llvm_unreachable("Exit infinite loop"); } namespace upgrader { // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. class BitcodeErrorCategoryType : public std::error_category { const char *name() const noexcept override { return "llvm.bitcode"; } std::string message(int IE) const override { BitcodeError E = static_cast(IE); switch (E) { case BitcodeError::CorruptedBitcode: return "Corrupted bitcode"; } llvm_unreachable("Unknown error type!"); } }; static ManagedStatic ErrorCategory; const std::error_category &BitcodeErrorCategory() { return *ErrorCategory; } static Expected readBlobInRecord(BitstreamCursor &Stream, unsigned Block, unsigned RecordID) { if (Error Err = Stream.EnterSubBlock(Block)) return std::move(Err); StringRef Strtab; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: return Strtab; case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Error Err = Stream.SkipBlock()) return std::move(Err); break; case BitstreamEntry::Record: StringRef Blob; SmallVector Record; Expected MaybeRecord = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecord) return MaybeRecord.takeError(); if (MaybeRecord.get() == RecordID) Strtab = Blob; break; } } } //===----------------------------------------------------------------------===// // External interface //===----------------------------------------------------------------------===// Expected> getBitcodeModuleList(MemoryBufferRef Buffer) { auto FOrErr = upgrader::getBitcodeFileContents(Buffer); if (!FOrErr) return FOrErr.takeError(); return std::move(FOrErr->Mods); } Expected getBitcodeFileContents(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); BitstreamCursor &Stream = *StreamOrErr; BitcodeFileContents F; while (true) { uint64_t BCBegin = Stream.getCurrentByteNo(); // We may be consuming bitcode from a client that leaves garbage at the end // of the bitcode stream. If we are close enough to // the end that there cannot possibly be another module, stop looking. if (BCBegin + 8 >= Stream.getBitcodeBytes().size()) return F; Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: { uint64_t IdentificationBit = -1ull; if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) { IdentificationBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Error Err = Stream.SkipBlock()) return std::move(Err); { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); Entry = MaybeEntry.get(); } if (Entry.Kind != BitstreamEntry::SubBlock || Entry.ID != bitc::MODULE_BLOCK_ID) return error("Malformed block"); } if (Entry.ID == bitc::MODULE_BLOCK_ID) { uint64_t ModuleBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Error Err = Stream.SkipBlock()) return std::move(Err); F.Mods.push_back({Stream.getBitcodeBytes().slice( BCBegin, Stream.getCurrentByteNo() - BCBegin), Buffer.getBufferIdentifier(), IdentificationBit, ModuleBit}); continue; } if (Entry.ID == bitc::STRTAB_BLOCK_ID) { Expected Strtab = readBlobInRecord(Stream, bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB); if (!Strtab) return Strtab.takeError(); // This string table is used by every preceding bitcode module that does // not have its own string table. A bitcode file may have multiple // string tables if it was created by binary concatenation, for example // with "llvm-cat -b". for (auto I = F.Mods.rbegin(), E = F.Mods.rend(); I != E; ++I) { if (!I->Strtab.empty()) break; I->Strtab = *Strtab; } // Similarly, the string table is used by every preceding symbol table; // normally there will be just one unless the bitcode file was created // by binary concatenation. if (!F.Symtab.empty() && F.StrtabForSymtab.empty()) F.StrtabForSymtab = *Strtab; continue; } if (Entry.ID == bitc::SYMTAB_BLOCK_ID) { Expected SymtabOrErr = readBlobInRecord(Stream, bitc::SYMTAB_BLOCK_ID, bitc::SYMTAB_BLOB); if (!SymtabOrErr) return SymtabOrErr.takeError(); // We can expect the bitcode file to have multiple symbol tables if it // was created by binary concatenation. In that case we silently // ignore any subsequent symbol tables, which is fine because this is a // low level function. The client is expected to notice that the number // of modules in the symbol table does not match the number of modules // in the input file and regenerate the symbol table. if (F.Symtab.empty()) F.Symtab = *SymtabOrErr; continue; } if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; } case BitstreamEntry::Record: if (Expected StreamFailed = Stream.skipRecord(Entry.ID)) continue; else return StreamFailed.takeError(); } } } /// Get a lazy one-at-time loading module from bitcode. /// /// This isn't always used in a lazy context. In particular, it's also used by /// \a parseModule(). If this is truly lazy, then we need to eagerly pull /// in forward-referenced functions from block address references. /// /// \param[in] MaterializeAll Set to \c true if we should materialize /// everything. Expected> BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting) { BitstreamCursor Stream(Buffer); std::string ProducerIdentification; if (IdentificationBit != -1ull) { if (Error JumpFailed = Stream.JumpToBit(IdentificationBit)) return std::move(JumpFailed); Expected ProducerIdentificationOrErr = readIdentificationBlock(Stream); if (!ProducerIdentificationOrErr) return ProducerIdentificationOrErr.takeError(); ProducerIdentification = *ProducerIdentificationOrErr; } if (Error JumpFailed = Stream.JumpToBit(ModuleBit)) return std::move(JumpFailed); auto *R = new BitcodeReader(std::move(Stream), Strtab, ProducerIdentification, Context); std::unique_ptr M = std::make_unique(ModuleIdentifier, Context); M->setMaterializer(R); // Delay parsing Metadata if ShouldLazyLoadMetadata is true. if (Error Err = R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata, IsImporting)) return std::move(Err); if (MaterializeAll) { // Read in the entire module, and destroy the BitcodeReader. if (Error Err = M->materializeAll()) return std::move(Err); } else { // Resolve forward references from blockaddresses. if (Error Err = R->materializeForwardReferencedFunctions()) return std::move(Err); } return std::move(M); } Expected> BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { return getModuleImpl(Context, false, ShouldLazyLoadMetadata, IsImporting); } // Parse the specified bitcode buffer and merge the index into CombinedIndex. // We don't use ModuleIdentifier here because the client may need to control the // module path used in the combined summary (e.g. when reading summaries for // regular LTO modules). Error BitcodeModule::readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, uint64_t ModuleId) { BitstreamCursor Stream(Buffer); if (Error JumpFailed = Stream.JumpToBit(ModuleBit)) return JumpFailed; ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, CombinedIndex, ModulePath, ModuleId); return R.parseModule(); } // Parse the specified bitcode buffer, returning the function info index. Expected> BitcodeModule::getSummary() { BitstreamCursor Stream(Buffer); if (Error JumpFailed = Stream.JumpToBit(ModuleBit)) return std::move(JumpFailed); auto Index = std::make_unique(/*HaveGVs=*/false); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, *Index, ModuleIdentifier, 0); if (Error Err = R.parseModule()) return std::move(Err); return std::move(Index); } static Expected getEnableSplitLTOUnitFlag(BitstreamCursor &Stream, unsigned ID) { if (Error Err = Stream.EnterSubBlock(ID)) return std::move(Err); SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // If no flags record found, conservatively return true to mimic // behavior before this flag was added. return true; case BitstreamEntry::Record: // The interesting case. break; } // Look for the FS_FLAGS record. Record.clear(); Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (MaybeBitCode.get()) { default: // Default behavior: ignore. break; case bitc::FS_FLAGS: { // [flags] uint64_t Flags = Record[0]; // Scan flags. IGC_ASSERT(Flags <= 0x3f && "Unexpected bits in flag"); return Flags & 0x8; } } } llvm_unreachable("Exit infinite loop"); } // Check if the given bitcode buffer contains a global value summary block. Expected BitcodeModule::getLTOInfo() { BitstreamCursor Stream(Buffer); if (Error JumpFailed = Stream.JumpToBit(ModuleBit)) return std::move(JumpFailed); if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return std::move(Err); while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false, /*EnableSplitLTOUnit=*/false}; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) { Expected EnableSplitLTOUnit = getEnableSplitLTOUnitFlag(Stream, Entry.ID); if (!EnableSplitLTOUnit) return EnableSplitLTOUnit.takeError(); return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true, *EnableSplitLTOUnit}; } if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) { Expected EnableSplitLTOUnit = getEnableSplitLTOUnitFlag(Stream, Entry.ID); if (!EnableSplitLTOUnit) return EnableSplitLTOUnit.takeError(); return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true, *EnableSplitLTOUnit}; } // Ignore other sub-blocks. if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; case BitstreamEntry::Record: if (Expected StreamFailed = Stream.skipRecord(Entry.ID)) continue; else return StreamFailed.takeError(); } } } static Expected getSingleModule(MemoryBufferRef Buffer) { Expected> MsOrErr = upgrader::getBitcodeModuleList(Buffer); if (!MsOrErr) return MsOrErr.takeError(); if (MsOrErr->size() != 1) return error("Expected a single module"); return (*MsOrErr)[0]; } Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLazyModule(Context, ShouldLazyLoadMetadata, IsImporting); } Expected> getOwningLazyBitcodeModule( std::unique_ptr &&Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { auto MOrErr = upgrader::getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata, IsImporting); if (MOrErr) (*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer)); return MOrErr; } Expected> BitcodeModule::parseModule(LLVMContext &Context) { return getModuleImpl(Context, true, false, false); // TODO: Restore the use-lists to the in-memory state when the bitcode was // written. We must defer until the Module has been fully materialized. } Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->parseModule(Context); } Expected getBitcodeTargetTriple(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readTriple(*StreamOrErr); } Expected isBitcodeContainingObjCCategory(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return hasObjCCategory(*StreamOrErr); } Expected getBitcodeProducerString(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readIdentificationCode(*StreamOrErr); } Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, uint64_t ModuleId) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->readSummary(CombinedIndex, BM->getModuleIdentifier(), ModuleId); } Expected> getModuleSummaryIndex(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getSummary(); } Expected getBitcodeLTOInfo(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLTOInfo(); } Expected> getModuleSummaryIndexForFile(StringRef Path, bool IgnoreEmptyThinLTOIndexFile) { ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path); if (!FileOrErr) return errorCodeToError(FileOrErr.getError()); if (IgnoreEmptyThinLTOIndexFile && !(*FileOrErr)->getBufferSize()) return nullptr; return upgrader::getModuleSummaryIndex(**FileOrErr); } }intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm10/BitcodeReader.h000066400000000000000000000246671363533017100273370ustar00rootroot00000000000000//===- llvm/Bitcode/BitcodeReader.h - Bitcode reader ------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This header defines interfaces to read LLVM bitcode files/streams. // //===----------------------------------------------------------------------===// #ifndef __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #define __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitCodes.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" #include #include #include #include #include namespace upgrader { using namespace llvm; struct BitcodeFileContents; /// Basic information extracted from a bitcode module to be used for LTO. struct BitcodeLTOInfo { bool IsThinLTO; bool HasSummary; bool EnableSplitLTOUnit; }; /// Represents a module in a bitcode file. class BitcodeModule { // This covers the identification (if present) and module blocks. ArrayRef Buffer; StringRef ModuleIdentifier; // The string table used to interpret this module. StringRef Strtab; // The bitstream location of the IDENTIFICATION_BLOCK. uint64_t IdentificationBit; // The bitstream location of this module's MODULE_BLOCK. uint64_t ModuleBit; BitcodeModule(ArrayRef Buffer, StringRef ModuleIdentifier, uint64_t IdentificationBit, uint64_t ModuleBit) : Buffer(Buffer), ModuleIdentifier(ModuleIdentifier), IdentificationBit(IdentificationBit), ModuleBit(ModuleBit) {} // Calls the ctor. friend Expected getBitcodeFileContents(MemoryBufferRef Buffer); Expected> getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting); public: StringRef getBuffer() const { return StringRef((const char *)Buffer.begin(), Buffer.size()); } StringRef getStrtab() const { return Strtab; } StringRef getModuleIdentifier() const { return ModuleIdentifier; } /// Read the bitcode module and prepare for lazy deserialization of function /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well. /// If IsImporting is true, this module is being parsed for ThinLTO /// importing into another module. Expected> getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting); /// Read the entire bitcode module and return it. Expected> parseModule(LLVMContext &Context); /// Returns information about the module to be used for LTO: whether to /// compile with ThinLTO, and whether it has a summary. Expected getLTOInfo(); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getSummary(); /// Parse the specified bitcode buffer and merge its module summary index /// into CombinedIndex. Error readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, uint64_t ModuleId); }; struct BitcodeFileContents { std::vector Mods; StringRef Symtab, StrtabForSymtab; }; /// Returns the contents of a bitcode file. This includes the raw contents of /// the symbol table embedded in the bitcode file. Clients which require a /// symbol table should prefer to use irsymtab::read instead of this function /// because it creates a reader for the irsymtab and handles upgrading bitcode /// files without a symbol table or with an old symbol table. Expected getBitcodeFileContents(MemoryBufferRef Buffer); /// Returns a list of modules in the specified bitcode buffer. Expected> getBitcodeModuleList(MemoryBufferRef Buffer); /// Read the header of the specified bitcode buffer and prepare for lazy /// deserialization of function bodies. If ShouldLazyLoadMetadata is true, /// lazily load metadata as well. If IsImporting is true, this module is /// being parsed for ThinLTO importing into another module. Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); /// Like getLazyBitcodeModule, except that the module takes ownership of /// the memory buffer if successful. If successful, this moves Buffer. On /// error, this *does not* move Buffer. If IsImporting is true, this module is /// being parsed for ThinLTO importing into another module. Expected> getOwningLazyBitcodeModule( std::unique_ptr &&Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); /// Read the header of the specified bitcode buffer and extract just the /// triple information. If successful, this returns a string. On error, this /// returns "". Expected getBitcodeTargetTriple(MemoryBufferRef Buffer); /// Return true if \p Buffer contains a bitcode file with ObjC code (category /// or class) in it. Expected isBitcodeContainingObjCCategory(MemoryBufferRef Buffer); /// Read the header of the specified bitcode buffer and extract just the /// producer string information. If successful, this returns a string. On /// error, this returns "". Expected getBitcodeProducerString(MemoryBufferRef Buffer); /// Read the specified bitcode file, returning the module. Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); #if 0 /// Returns LTO information for the specified bitcode file. Expected getBitcodeLTOInfo(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getModuleSummaryIndex(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer and merge the index into CombinedIndex. Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, uint64_t ModuleId); /// Parse the module summary index out of an IR file and return the module /// summary index object if found, or an empty summary if not. If Path refers /// to an empty file and IgnoreEmptyThinLTOIndexFile is true, then /// this function will return nullptr. Expected> getModuleSummaryIndexForFile(StringRef Path, bool IgnoreEmptyThinLTOIndexFile = false); /// isBitcodeWrapper - Return true if the given bytes are the magic bytes /// for an LLVM IR bitcode wrapper. inline bool isBitcodeWrapper(const unsigned char *BufPtr, const unsigned char *BufEnd) { // See if you can find the hidden message in the magic bytes :-). // (Hint: it's a little-endian encoding.) return BufPtr != BufEnd && BufPtr[0] == 0xDE && BufPtr[1] == 0xC0 && BufPtr[2] == 0x17 && BufPtr[3] == 0x0B; } /// isRawBitcode - Return true if the given bytes are the magic bytes for /// raw LLVM IR bitcode (without a wrapper). inline bool isRawBitcode(const unsigned char *BufPtr, const unsigned char *BufEnd) { // These bytes sort of have a hidden message, but it's not in // little-endian this time, and it's a little redundant. return BufPtr != BufEnd && BufPtr[0] == 'B' && BufPtr[1] == 'C' && BufPtr[2] == 0xc0 && BufPtr[3] == 0xde; } /// isBitcode - Return true if the given bytes are the magic bytes for /// LLVM IR bitcode, either with or without a wrapper. inline bool isBitcode(const unsigned char *BufPtr, const unsigned char *BufEnd) { return isBitcodeWrapper(BufPtr, BufEnd) || isRawBitcode(BufPtr, BufEnd); } /// SkipBitcodeWrapperHeader - Some systems wrap bc files with a special /// header for padding or other reasons. The format of this header is: /// /// struct bc_header { /// uint32_t Magic; // 0x0B17C0DE /// uint32_t Version; // Version, currently always 0. /// uint32_t BitcodeOffset; // Offset to traditional bitcode file. /// uint32_t BitcodeSize; // Size of traditional bitcode file. /// ... potentially other gunk ... /// }; /// /// This function is called when we find a file with a matching magic number. /// In this case, skip down to the subsection of the file that is actually a /// BC file. /// If 'VerifyBufferSize' is true, check that the buffer is large enough to /// contain the whole bitcode file. inline bool SkipBitcodeWrapperHeader(const unsigned char *&BufPtr, const unsigned char *&BufEnd, bool VerifyBufferSize) { // Must contain the offset and size field! if (unsigned(BufEnd - BufPtr) < BWH_SizeField + 4) return true; unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]); unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]); uint64_t BitcodeOffsetEnd = (uint64_t)Offset + (uint64_t)Size; // Verify that Offset+Size fits in the file. if (VerifyBufferSize && BitcodeOffsetEnd > uint64_t(BufEnd-BufPtr)) return true; BufPtr += Offset; BufEnd = BufPtr+Size; return false; } const std::error_category &BitcodeErrorCategory(); enum class BitcodeError { CorruptedBitcode = 1 }; inline std::error_code make_error_code(BitcodeError E) { return std::error_code(static_cast(E), BitcodeErrorCategory()); } #endif } // end namespace llvm #endif // LLVM_BITCODE_BITCODEREADER_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm10/MetadataLoader.h000066400000000000000000000051341363533017100274760ustar00rootroot00000000000000//===-- Bitcode/Reader/MetadataLoader.h - Load Metadatas -------*- C++ -*-====// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This class handles loading Metadatas. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_METADATALOADER_H #define LLVM_LIB_BITCODE_READER_METADATALOADER_H #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Error.h" #include #include namespace llvm { class BitcodeReaderValueList; class BitstreamCursor; class DISubprogram; class Error; class Function; class Instruction; class Metadata; class MDNode; class Module; class Type; /// Helper class that handles loading Metadatas and keeping them available. class MetadataLoader { class MetadataLoaderImpl; std::unique_ptr Pimpl; Error parseMetadata(bool ModuleLevel); public: ~MetadataLoader(); MetadataLoader(BitstreamCursor &Stream, Module &TheModule, BitcodeReaderValueList &ValueList, bool IsImporting, std::function getTypeByID); MetadataLoader &operator=(MetadataLoader &&); MetadataLoader(MetadataLoader &&); // Parse a module metadata block Error parseModuleMetadata() { return parseMetadata(true); } // Parse a function metadata block Error parseFunctionMetadata() { return parseMetadata(false); } /// Set the mode to strip TBAA metadata on load. void setStripTBAA(bool StripTBAA = true); /// Return true if the Loader is stripping TBAA metadata. bool isStrippingTBAA(); // Return true there are remaining unresolved forward references. bool hasFwdRefs() const; /// Return the given metadata, creating a replaceable forward reference if /// necessary. Metadata *getMetadataFwdRefOrLoad(unsigned Idx); /// Return the DISubprogram metadata for a Function if any, null otherwise. DISubprogram *lookupSubprogramForFunction(Function *F); /// Parse a `METADATA_ATTACHMENT` block for a function. Error parseMetadataAttachment( Function &F, const SmallVectorImpl &InstructionList); /// Parse a `METADATA_KIND` block for the current module. Error parseMetadataKinds(); unsigned size() const; void shrinkTo(unsigned N); /// Perform bitcode upgrades on llvm.dbg.* calls. void upgradeDebugIntrinsics(Function &F); }; } #endif // LLVM_LIB_BITCODE_READER_METADATALOADER_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm10/Upgrader.cpp000066400000000000000000000043221363533017100267310ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "Upgrader.h" #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include #include #include "common/LLVMWarningsPop.hpp" using namespace llvm; std::unique_ptr upgrader::upgradeBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { auto ErrM = upgrader::parseBitcodeFile(Buffer, Context); Module *M = ErrM.get().get(); if (!M) return nullptr; SmallVector Buf; Buf.reserve(1024*1024); raw_svector_ostream OS(Buf); WriteBitcodeToFile(*M, OS); return MemoryBuffer::getMemBufferCopy(OS.str()); } Expected> upgrader::upgradeAndParseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { return upgrader::parseBitcodeFile(Buffer, Context); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm10/Upgrader.h000066400000000000000000000036741363533017100264070ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #ifndef __DRIVERINTERFACE_UPGRADER_H__ #define __DRIVERINTERFACE_UPGRADER_H__ #include "common/LLVMWarningsPush.hpp" #include #include #include #include #include "common/LLVMWarningsPop.hpp" namespace upgrader { llvm::Expected> parseBitcodeFile(llvm::MemoryBufferRef Buffer, llvm::LLVMContext &Context); std::unique_ptr upgradeBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); llvm::Expected> upgradeAndParseBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); } // End upgrader namespace #endif // __DRIVERINTERFACE_UPGRADER_H__ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm10/ValueList.h000066400000000000000000000065411363533017100265420ustar00rootroot00000000000000//===-- Bitcode/Reader/ValueList.h - Number values --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This class gives values and types Unique ID's. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_VALUELIST_H #define LLVM_LIB_BITCODE_READER_VALUELIST_H #include "llvm/IR/ValueHandle.h" #include #include #include "Probe.h" namespace llvm { class Constant; class LLVMContext; class Type; class Value; class BitcodeReaderValueList { std::vector ValuePtrs; /// Struct containing fully-specified copies of the type of each /// value. When pointers are opaque, this will be contain non-opaque /// variants so that restructuring instructions can determine their /// type correctly even if being loaded from old bitcode where some /// types are implicit. std::vector FullTypes; /// As we resolve forward-referenced constants, we add information about them /// to this vector. This allows us to resolve them in bulk instead of /// resolving each reference at a time. See the code in /// ResolveConstantForwardRefs for more information about this. /// /// The key of this vector is the placeholder constant, the value is the slot /// number that holds the resolved value. using ResolveConstantsTy = std::vector>; ResolveConstantsTy ResolveConstants; LLVMContext &Context; /// Maximum number of valid references. Forward references exceeding the /// maximum must be invalid. unsigned RefsUpperBound; public: BitcodeReaderValueList(LLVMContext &C, size_t RefsUpperBound) : Context(C), RefsUpperBound(std::min((size_t)std::numeric_limits::max(), RefsUpperBound)) {} ~BitcodeReaderValueList() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); } // vector compatibility methods unsigned size() const { return ValuePtrs.size(); } void resize(unsigned N) { ValuePtrs.resize(N); FullTypes.resize(N); } void push_back(Value *V, Type *Ty) { ValuePtrs.emplace_back(V); FullTypes.emplace_back(Ty); } void clear() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); ValuePtrs.clear(); FullTypes.clear(); } Value *operator[](unsigned i) const { IGC_ASSERT(i < ValuePtrs.size()); return ValuePtrs[i]; } Value *back() const { return ValuePtrs.back(); } void pop_back() { ValuePtrs.pop_back(); FullTypes.pop_back(); } bool empty() const { return ValuePtrs.empty(); } void shrinkTo(unsigned N) { IGC_ASSERT(N <= size() && "Invalid shrinkTo request!"); ValuePtrs.resize(N); FullTypes.resize(N); } Constant *getConstantFwdRef(unsigned Idx, Type *Ty); Value *getValueFwdRef(unsigned Idx, Type *Ty, Type **FullTy = nullptr); void assignValue(Value *V, unsigned Idx, Type *FullTy); /// Once all constants are read, this method bulk resolves any forward /// references. void resolveConstantForwardRefs(); }; } // end namespace llvm #endif // LLVM_LIB_BITCODE_READER_VALUELIST_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm4/000077500000000000000000000000001363533017100243765ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm4/BitcodeReader.cpp000066400000000000000000006074721363533017100276160ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "MetadataLoader.h" #include "ValueList.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalIndirectSymbol.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/OperandTraits.h" #include "llvm/IR/Operator.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/Type.h" #include "llvm/IR/ValueHandle.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "common/LLVMWarningsPop.hpp" #include "BitcodeReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "Probe.h" using namespace llvm; //===----------------------------------------------------------------------===// // Since LLVM 3.6, reading 3.4 based bitcode fails due to header checks. // Instead of overriding the defaul BitcodeReader which is part of LLVM source // tree located at lib/Bitcode/.... We copy the existing implementation and // modify the interfaces as per need. //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // upgrade bitcast to addrspacecast when necessary //===----------------------------------------------------------------------===// Instruction *upgradeBitCastInst(unsigned Opc, Value *V, Type *DestTy, Instruction *&Temp) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = V->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return CastInst::Create(Instruction::AddrSpaceCast, V, DestTy); } return nullptr; } Value *upgradeBitCastExpr(unsigned Opc, Constant *C, Type *DestTy) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = C->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return ConstantExpr::getAddrSpaceCast(C, DestTy); } return nullptr; } namespace { enum { SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; Error error(const Twine &Message) { return make_error( Message, make_error_code(BitcodeError::CorruptedBitcode)); } /// Helper to read the header common to all bitcode files. bool hasValidBitcodeHeader(BitstreamCursor &Stream) { // Sniff for the signature. if (!Stream.canSkipToPos(4) || Stream.Read(8) != 'B' || Stream.Read(8) != 'C' || Stream.Read(4) != 0x0 || Stream.Read(4) != 0xC || Stream.Read(4) != 0xE || Stream.Read(4) != 0xD) return false; return true; } Expected initStream(MemoryBufferRef Buffer) { const unsigned char *BufPtr = (const unsigned char *)Buffer.getBufferStart(); const unsigned char *BufEnd = BufPtr + Buffer.getBufferSize(); if (Buffer.getBufferSize() & 3) return error("Invalid bitcode signature"); // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. if (isBitcodeWrapper(BufPtr, BufEnd)) if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) return error("Invalid bitcode wrapper header"); BitstreamCursor Stream(ArrayRef(BufPtr, BufEnd)); if (!hasValidBitcodeHeader(Stream)) return error("Invalid bitcode signature"); return std::move(Stream); } /// Convert a string from a record into an std::string, return true on failure. template static bool convertToString(ArrayRef Record, unsigned Idx, StrTy &Result) { if (Idx > Record.size()) return true; for (unsigned i = Idx, e = Record.size(); i != e; ++i) Result += (char)Record[i]; return false; } // Strip all the TBAA attachment for the module. void stripTBAA(Module *M) { for (auto &F : *M) { if (F.isMaterializable()) continue; for (auto &I : instructions(F)) I.setMetadata(LLVMContext::MD_tbaa, nullptr); } } /// Read the "IDENTIFICATION_BLOCK_ID" block, do some basic enforcement on the /// "epoch" encoded in the bitcode, and return the producer name if any. Expected readIdentificationBlock(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::IDENTIFICATION_BLOCK_ID)) return error("Invalid record"); // Read all the records. SmallVector Record; std::string ProducerIdentification; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { default: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ProducerIdentification; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: reject return error("Invalid value"); case bitc::IDENTIFICATION_CODE_STRING: // IDENTIFICATION: [strchr x N] convertToString(Record, 0, ProducerIdentification); break; case bitc::IDENTIFICATION_CODE_EPOCH: { // EPOCH: [epoch#] unsigned epoch = (unsigned)Record[0]; if (epoch != bitc::BITCODE_CURRENT_EPOCH) { return error( Twine("Incompatible epoch: Bitcode '") + Twine(epoch) + "' vs current: '" + Twine(bitc::BITCODE_CURRENT_EPOCH) + "'"); } } } } } Expected readIdentificationCode(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { if (Stream.AtEndOfStream()) return ""; BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) return readIdentificationBlock(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } Expected hasObjCCategoryInModule(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. switch (Stream.readRecord(Entry.ID, Record)) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Check for the i386 and other (x86_64, ARM) conventions if (S.find("__DATA, __objc_catlist") != std::string::npos || S.find("__OBJC,__category") != std::string::npos) return true; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } Expected hasObjCCategory(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return hasObjCCategoryInModule(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } Expected readModuleTriple(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; std::string Triple; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Triple; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. switch (Stream.readRecord(Entry.ID, Record)) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); Triple = S; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } Expected readTriple(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ""; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return readModuleTriple(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } class BitcodeReaderBase { protected: BitcodeReaderBase(BitstreamCursor Stream) : Stream(std::move(Stream)) { this->Stream.setBlockInfo(&BlockInfo); } BitstreamBlockInfo BlockInfo; BitstreamCursor Stream; bool readBlockInfo(); // Contains an arbitrary and optional string identifying the bitcode producer std::string ProducerIdentification; Error error(const Twine &Message); }; Error BitcodeReaderBase::error(const Twine &Message) { std::string FullMsg = Message.str(); if (!ProducerIdentification.empty()) FullMsg += " (Producer: '" + ProducerIdentification + "' Reader: 'LLVM " + LLVM_VERSION_STRING "')"; return ::error(FullMsg); } class BitcodeReader : public BitcodeReaderBase, public GVMaterializer { LLVMContext &Context; Module *TheModule = nullptr; // Next offset to start scanning for lazy parsing of function bodies. uint64_t NextUnreadBit = 0; // Last function offset found in the VST. uint64_t LastFunctionBlockBit = 0; bool SeenValueSymbolTable = false; uint64_t VSTOffset = 0; std::vector TypeList; BitcodeReaderValueList ValueList; Optional MDLoader; std::vector ComdatList; SmallVector InstructionList; std::vector > GlobalInits; std::vector > IndirectSymbolInits; std::vector > FunctionPrefixes; std::vector > FunctionPrologues; std::vector > FunctionPersonalityFns; /// The set of attributes by index. Index zero in the file is for null, and /// is thus not represented here. As such all indices are off by one. std::vector MAttributes; /// The set of attribute groups. std::map MAttributeGroups; /// While parsing a function body, this is a list of the basic blocks for the /// function. std::vector FunctionBBs; // When reading the module header, this list is populated with functions that // have bodies later in the file. std::vector FunctionsWithBodies; // When intrinsic functions are encountered which require upgrading they are // stored here with their replacement function. typedef DenseMap UpdatedIntrinsicMap; UpdatedIntrinsicMap UpgradedIntrinsics; // Intrinsics which were remangled because of types rename UpdatedIntrinsicMap RemangledIntrinsics; // Several operations happen after the module header has been read, but // before function bodies are processed. This keeps track of whether // we've done this yet. bool SeenFirstFunctionBody = false; /// When function bodies are initially scanned, this map contains info about /// where to find deferred function body in the stream. DenseMap DeferredFunctionInfo; /// When Metadata block is initially scanned when parsing the module, we may /// choose to defer parsing of the metadata. This vector contains info about /// which Metadata blocks are deferred. std::vector DeferredMetadataInfo; /// These are basic blocks forward-referenced by block addresses. They are /// inserted lazily into functions when they're loaded. The basic block ID is /// its index into the vector. DenseMap> BasicBlockFwdRefs; std::deque BasicBlockFwdRefQueue; /// Indicates that we are using a new encoding for instruction operands where /// most operands in the current FUNCTION_BLOCK are encoded relative to the /// instruction number, for a more compact encoding. Some instruction /// operands are not relative to the instruction ID: basic block numbers, and /// types. Once the old style function blocks have been phased out, we would /// not need this flag. bool UseRelativeIDs = false; /// True if all functions will be materialized, negating the need to process /// (e.g.) blockaddress forward references. bool WillMaterializeAllForwardRefs = false; bool StripDebugInfo = false; TBAAVerifier TBAAVerifyHelper; std::vector BundleTags; public: BitcodeReader(BitstreamCursor Stream, StringRef ProducerIdentification, LLVMContext &Context); Error materializeForwardReferencedFunctions(); Error materialize(GlobalValue *GV) override; Error materializeModule() override; std::vector getIdentifiedStructTypes() const override; /// \brief Main interface to parsing a bitcode buffer. /// \returns true if an error occurred. Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); static uint64_t decodeSignRotatedValue(uint64_t V); /// Materialize any deferred Metadata block. Error materializeMetadata() override; void setStripDebugInfo() override; private: std::vector IdentifiedStructTypes; StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); StructType *createIdentifiedStructType(LLVMContext &Context); Type *getTypeByID(unsigned ID); Value *getFnValueByID(unsigned ID, Type *Ty) { if (Ty && Ty->isMetadataTy()) return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); return ValueList.getValueFwdRef(ID, Ty); } Metadata *getFnMetadataByID(unsigned ID) { return MDLoader->getMetadataFwdRefOrLoad(ID); } BasicBlock *getBasicBlock(unsigned ID) const { if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID return FunctionBBs[ID]; } AttributeSet getAttributes(unsigned i) const { if (i-1 < MAttributes.size()) return MAttributes[i-1]; return AttributeSet(); } /// Read a value/type pair out of the specified record from slot 'Slot'. /// Increment Slot past the number of slots used in the record. Return true on /// failure. bool getValueTypePair(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Value *&ResVal) { if (Slot == Record.size()) return true; unsigned ValNo = (unsigned)Record[Slot++]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; if (ValNo < InstNum) { // If this is not a forward reference, just return the value we already // have. ResVal = getFnValueByID(ValNo, nullptr); return ResVal == nullptr; } if (Slot == Record.size()) return true; unsigned TypeNo = (unsigned)Record[Slot++]; ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo)); return ResVal == nullptr; } /// Read a value out of the specified record from slot 'Slot'. Increment Slot /// past the number of slots used by the value in the record. Return true if /// there is an error. bool popValue(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { if (getValue(Record, Slot, InstNum, Ty, ResVal)) return true; // All values currently take a single record slot. ++Slot; return false; } /// Like popValue, but does not increment the Slot number. bool getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { ResVal = getValue(Record, Slot, InstNum, Ty); return ResVal == nullptr; } /// Version of getValue that returns ResVal directly, or 0 if there is an /// error. Value *getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)Record[Slot]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Like getValue, but decodes signed VBRs. Value *getValueSigned(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)decodeSignRotatedValue(Record[Slot]); // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Converts alignment exponent (i.e. power of two (or zero)) to the /// corresponding alignment to use. If alignment is too large, returns /// a corresponding error code. Error parseAlignmentValue(uint64_t Exponent, unsigned &Alignment); Error parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind); Error parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata = false); Error parseAttributeBlock(); Error parseAttributeGroupBlock(); Error parseTypeTable(); Error parseTypeTableBody(); Error parseOperandBundleTags(); Expected recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT); Error parseValueSymbolTable(uint64_t Offset = 0); Error parseConstants(); Error rememberAndSkipFunctionBodies(); Error rememberAndSkipFunctionBody(); /// Save the positions of the Metadata blocks and skip parsing the blocks. Error rememberAndSkipMetadata(); Error typeCheckLoadStoreInst(Type *ValType, Type *PtrType); Error parseFunctionBody(Function *F); Error globalCleanup(); Error resolveGlobalAndIndirectSymbolInits(); Error parseUseLists(); Error findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator); }; /// Class to manage reading and parsing function summary index bitcode /// files/sections. class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase { /// The module index built during parsing. ModuleSummaryIndex &TheIndex; /// Indicates whether we have encountered a global value summary section /// yet during parsing. bool SeenGlobalValSummary = false; /// Indicates whether we have already parsed the VST, used for error checking. bool SeenValueSymbolTable = false; /// Set to the offset of the VST recorded in the MODULE_CODE_VSTOFFSET record. /// Used to enable on-demand parsing of the VST. uint64_t VSTOffset = 0; // Map to save ValueId to GUID association that was recorded in the // ValueSymbolTable. It is used after the VST is parsed to convert // call graph edges read from the function summary from referencing // callees by their ValueId to using the GUID instead, which is how // they are recorded in the summary index being built. // We save a second GUID which is the same as the first one, but ignoring the // linkage, i.e. for value other than local linkage they are identical. DenseMap> ValueIdToCallGraphGUIDMap; /// Map populated during module path string table parsing, from the /// module ID to a string reference owned by the index's module /// path string table, used to correlate with combined index /// summary records. DenseMap ModuleIdMap; /// Original source file name recorded in a bitcode record. std::string SourceFileName; public: ModuleSummaryIndexBitcodeReader( BitstreamCursor Stream, ModuleSummaryIndex &TheIndex); Error parseModule(StringRef ModulePath); private: Error parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap); std::vector makeRefList(ArrayRef Record); std::vector makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile); Error parseEntireSummary(StringRef ModulePath); Error parseModuleStringTable(); std::pair getGUIDFromValueId(unsigned ValueId); }; } // end anonymous namespace #if 0 std::error_code llvm::errorToErrorCodeAndEmitErrors(LLVMContext &Ctx, Error Err) { if (Err) { std::error_code EC; handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { EC = EIB.convertToErrorCode(); Ctx.emitError(EIB.message()); }); return EC; } return std::error_code(); } #endif BitcodeReader::BitcodeReader(BitstreamCursor Stream, StringRef ProducerIdentification, LLVMContext &Context) : BitcodeReaderBase(std::move(Stream)), Context(Context), ValueList(Context) { this->ProducerIdentification = ProducerIdentification; } Error BitcodeReader::materializeForwardReferencedFunctions() { if (WillMaterializeAllForwardRefs) return Error::success(); // Prevent recursion. WillMaterializeAllForwardRefs = true; while (!BasicBlockFwdRefQueue.empty()) { Function *F = BasicBlockFwdRefQueue.front(); BasicBlockFwdRefQueue.pop_front(); IGC_ASSERT(F && "Expected valid function"); if (!BasicBlockFwdRefs.count(F)) // Already materialized. continue; // Check for a function that isn't materializable to prevent an infinite // loop. When parsing a blockaddress stored in a global variable, there // isn't a trivial way to check if a function will have a body without a // linear search through FunctionsWithBodies, so just check it here. if (!F->isMaterializable()) return error("Never resolved function from blockaddress"); // Try to materialize F. if (Error Err = materialize(F)) return Err; } IGC_ASSERT(BasicBlockFwdRefs.empty() && "Function missing from queue"); // Reset state. WillMaterializeAllForwardRefs = false; return Error::success(); } //===----------------------------------------------------------------------===// // Helper functions to implement forward reference resolution, etc. //===----------------------------------------------------------------------===// static bool hasImplicitComdat(size_t Val) { switch (Val) { default: return false; case 1: // Old WeakAnyLinkage case 4: // Old LinkOnceAnyLinkage case 10: // Old WeakODRLinkage case 11: // Old LinkOnceODRLinkage return true; } } static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) { switch (Val) { default: // Map unknown/new linkages to external case 0: return GlobalValue::ExternalLinkage; case 2: return GlobalValue::AppendingLinkage; case 3: return GlobalValue::InternalLinkage; case 5: return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage case 6: return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage case 7: return GlobalValue::ExternalWeakLinkage; case 8: return GlobalValue::CommonLinkage; case 9: return GlobalValue::PrivateLinkage; case 12: return GlobalValue::AvailableExternallyLinkage; case 13: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage case 14: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateWeakLinkage case 15: return GlobalValue::ExternalLinkage; // Obsolete LinkOnceODRAutoHideLinkage case 1: // Old value with implicit comdat. case 16: return GlobalValue::WeakAnyLinkage; case 10: // Old value with implicit comdat. case 17: return GlobalValue::WeakODRLinkage; case 4: // Old value with implicit comdat. case 18: return GlobalValue::LinkOnceAnyLinkage; case 11: // Old value with implicit comdat. case 19: return GlobalValue::LinkOnceODRLinkage; } } /// Decode the flags for GlobalValue in the summary. static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags, uint64_t Version) { // Summary were not emitted before LLVM 3.9, we don't need to upgrade Linkage // like getDecodedLinkage() above. Any future change to the linkage enum and // to getDecodedLinkage() will need to be taken into account here as above. auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits RawFlags = RawFlags >> 4; bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3; // The LiveRoot flag wasn't introduced until version 3. For dead stripping // to work correctly on earlier versions, we must conservatively treat all // values as live. bool LiveRoot = (RawFlags & 0x2) || Version < 3; return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, LiveRoot); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { switch (Val) { default: // Map unknown visibilities to default. case 0: return GlobalValue::DefaultVisibility; case 1: return GlobalValue::HiddenVisibility; case 2: return GlobalValue::ProtectedVisibility; } } static GlobalValue::DLLStorageClassTypes getDecodedDLLStorageClass(unsigned Val) { switch (Val) { default: // Map unknown values to default. case 0: return GlobalValue::DefaultStorageClass; case 1: return GlobalValue::DLLImportStorageClass; case 2: return GlobalValue::DLLExportStorageClass; } } static GlobalVariable::ThreadLocalMode getDecodedThreadLocalMode(unsigned Val) { switch (Val) { case 0: return GlobalVariable::NotThreadLocal; default: // Map unknown non-zero value to general dynamic. case 1: return GlobalVariable::GeneralDynamicTLSModel; case 2: return GlobalVariable::LocalDynamicTLSModel; case 3: return GlobalVariable::InitialExecTLSModel; case 4: return GlobalVariable::LocalExecTLSModel; } } static GlobalVariable::UnnamedAddr getDecodedUnnamedAddrType(unsigned Val) { switch (Val) { default: // Map unknown to UnnamedAddr::None. case 0: return GlobalVariable::UnnamedAddr::None; case 1: return GlobalVariable::UnnamedAddr::Global; case 2: return GlobalVariable::UnnamedAddr::Local; } } static int getDecodedCastOpcode(unsigned Val) { switch (Val) { default: return -1; case bitc::CAST_TRUNC : return Instruction::Trunc; case bitc::CAST_ZEXT : return Instruction::ZExt; case bitc::CAST_SEXT : return Instruction::SExt; case bitc::CAST_FPTOUI : return Instruction::FPToUI; case bitc::CAST_FPTOSI : return Instruction::FPToSI; case bitc::CAST_UITOFP : return Instruction::UIToFP; case bitc::CAST_SITOFP : return Instruction::SIToFP; case bitc::CAST_FPTRUNC : return Instruction::FPTrunc; case bitc::CAST_FPEXT : return Instruction::FPExt; case bitc::CAST_PTRTOINT: return Instruction::PtrToInt; case bitc::CAST_INTTOPTR: return Instruction::IntToPtr; case bitc::CAST_BITCAST : return Instruction::BitCast; case bitc::CAST_ADDRSPACECAST: return Instruction::AddrSpaceCast; } } static int getDecodedBinaryOpcode(unsigned Val, Type *Ty) { bool IsFP = Ty->isFPOrFPVectorTy(); // BinOps are only valid for int/fp or vector of int/fp types if (!IsFP && !Ty->isIntOrIntVectorTy()) return -1; switch (Val) { default: return -1; case bitc::BINOP_ADD: return IsFP ? Instruction::FAdd : Instruction::Add; case bitc::BINOP_SUB: return IsFP ? Instruction::FSub : Instruction::Sub; case bitc::BINOP_MUL: return IsFP ? Instruction::FMul : Instruction::Mul; case bitc::BINOP_UDIV: return IsFP ? -1 : Instruction::UDiv; case bitc::BINOP_SDIV: return IsFP ? Instruction::FDiv : Instruction::SDiv; case bitc::BINOP_UREM: return IsFP ? -1 : Instruction::URem; case bitc::BINOP_SREM: return IsFP ? Instruction::FRem : Instruction::SRem; case bitc::BINOP_SHL: return IsFP ? -1 : Instruction::Shl; case bitc::BINOP_LSHR: return IsFP ? -1 : Instruction::LShr; case bitc::BINOP_ASHR: return IsFP ? -1 : Instruction::AShr; case bitc::BINOP_AND: return IsFP ? -1 : Instruction::And; case bitc::BINOP_OR: return IsFP ? -1 : Instruction::Or; case bitc::BINOP_XOR: return IsFP ? -1 : Instruction::Xor; } } static AtomicRMWInst::BinOp getDecodedRMWOperation(unsigned Val) { switch (Val) { default: return AtomicRMWInst::BAD_BINOP; case bitc::RMW_XCHG: return AtomicRMWInst::Xchg; case bitc::RMW_ADD: return AtomicRMWInst::Add; case bitc::RMW_SUB: return AtomicRMWInst::Sub; case bitc::RMW_AND: return AtomicRMWInst::And; case bitc::RMW_NAND: return AtomicRMWInst::Nand; case bitc::RMW_OR: return AtomicRMWInst::Or; case bitc::RMW_XOR: return AtomicRMWInst::Xor; case bitc::RMW_MAX: return AtomicRMWInst::Max; case bitc::RMW_MIN: return AtomicRMWInst::Min; case bitc::RMW_UMAX: return AtomicRMWInst::UMax; case bitc::RMW_UMIN: return AtomicRMWInst::UMin; } } static AtomicOrdering getDecodedOrdering(unsigned Val) { switch (Val) { case bitc::ORDERING_NOTATOMIC: return AtomicOrdering::NotAtomic; case bitc::ORDERING_UNORDERED: return AtomicOrdering::Unordered; case bitc::ORDERING_MONOTONIC: return AtomicOrdering::Monotonic; case bitc::ORDERING_ACQUIRE: return AtomicOrdering::Acquire; case bitc::ORDERING_RELEASE: return AtomicOrdering::Release; case bitc::ORDERING_ACQREL: return AtomicOrdering::AcquireRelease; default: // Map unknown orderings to sequentially-consistent. case bitc::ORDERING_SEQCST: return AtomicOrdering::SequentiallyConsistent; } } static SynchronizationScope getDecodedSynchScope(unsigned Val) { switch (Val) { case bitc::SYNCHSCOPE_SINGLETHREAD: return SingleThread; default: // Map unknown scopes to cross-thread. case bitc::SYNCHSCOPE_CROSSTHREAD: return CrossThread; } } static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) { switch (Val) { default: // Map unknown selection kinds to any. case bitc::COMDAT_SELECTION_KIND_ANY: return Comdat::Any; case bitc::COMDAT_SELECTION_KIND_EXACT_MATCH: return Comdat::ExactMatch; case bitc::COMDAT_SELECTION_KIND_LARGEST: return Comdat::Largest; case bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES: return Comdat::NoDuplicates; case bitc::COMDAT_SELECTION_KIND_SAME_SIZE: return Comdat::SameSize; } } static FastMathFlags getDecodedFastMathFlags(unsigned Val) { FastMathFlags FMF; if (0 != (Val & FastMathFlags::AllowReassoc)) FMF.setAllowReassoc(); if (0 != (Val & FastMathFlags::NoNaNs)) FMF.setNoNaNs(); if (0 != (Val & FastMathFlags::NoInfs)) FMF.setNoInfs(); if (0 != (Val & FastMathFlags::NoSignedZeros)) FMF.setNoSignedZeros(); if (0 != (Val & FastMathFlags::AllowReciprocal)) FMF.setAllowReciprocal(); if (0 != (Val & FastMathFlags::AllowContract)) FMF.setAllowContract(true); if (0 != (Val & FastMathFlags::ApproxFunc)) FMF.setApproxFunc(); return FMF; } static void upgradeDLLImportExportLinkage(GlobalValue *GV, unsigned Val) { switch (Val) { case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break; case 6: GV->setDLLStorageClass(GlobalValue::DLLExportStorageClass); break; } } Type *BitcodeReader::getTypeByID(unsigned ID) { // The type table size is always specified correctly. if (ID >= TypeList.size()) return nullptr; if (Type *Ty = TypeList[ID]) return Ty; // If we have a forward reference, the only possible case is when it is to a // named struct. Just create a placeholder for now. return TypeList[ID] = createIdentifiedStructType(Context); } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context, StringRef Name) { auto *Ret = StructType::create(Context, Name); IdentifiedStructTypes.push_back(Ret); return Ret; } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) { auto *Ret = StructType::create(Context); IdentifiedStructTypes.push_back(Ret); return Ret; } //===----------------------------------------------------------------------===// // Functions for parsing blocks from the bitcode file //===----------------------------------------------------------------------===// static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { switch (Val) { case Attribute::EndAttrKinds: llvm_unreachable("Synthetic enumerators which should never get here"); case Attribute::None: return 0; case Attribute::ZExt: return 1 << 0; case Attribute::SExt: return 1 << 1; case Attribute::NoReturn: return 1 << 2; case Attribute::InReg: return 1 << 3; case Attribute::StructRet: return 1 << 4; case Attribute::NoUnwind: return 1 << 5; case Attribute::NoAlias: return 1 << 6; case Attribute::ByVal: return 1 << 7; case Attribute::Nest: return 1 << 8; case Attribute::ReadNone: return 1 << 9; case Attribute::ReadOnly: return 1 << 10; case Attribute::NoInline: return 1 << 11; case Attribute::AlwaysInline: return 1 << 12; case Attribute::OptimizeForSize: return 1 << 13; case Attribute::StackProtect: return 1 << 14; case Attribute::StackProtectReq: return 1 << 15; case Attribute::Alignment: return 31 << 16; case Attribute::NoCapture: return 1 << 21; case Attribute::NoRedZone: return 1 << 22; case Attribute::NoImplicitFloat: return 1 << 23; case Attribute::Naked: return 1 << 24; case Attribute::InlineHint: return 1 << 25; case Attribute::StackAlignment: return 7 << 26; case Attribute::ReturnsTwice: return 1 << 29; case Attribute::UWTable: return 1 << 30; case Attribute::NonLazyBind: return 1U << 31; case Attribute::SanitizeAddress: return 1ULL << 32; case Attribute::MinSize: return 1ULL << 33; case Attribute::NoDuplicate: return 1ULL << 34; case Attribute::StackProtectStrong: return 1ULL << 35; case Attribute::SanitizeThread: return 1ULL << 36; case Attribute::SanitizeMemory: return 1ULL << 37; case Attribute::NoBuiltin: return 1ULL << 38; case Attribute::Returned: return 1ULL << 39; case Attribute::Cold: return 1ULL << 40; case Attribute::Builtin: return 1ULL << 41; case Attribute::OptimizeNone: return 1ULL << 42; case Attribute::InAlloca: return 1ULL << 43; case Attribute::NonNull: return 1ULL << 44; case Attribute::JumpTable: return 1ULL << 45; case Attribute::Convergent: return 1ULL << 46; case Attribute::SafeStack: return 1ULL << 47; case Attribute::NoRecurse: return 1ULL << 48; case Attribute::InaccessibleMemOnly: return 1ULL << 49; case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50; case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; case Attribute::WriteOnly: return 1ULL << 53; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; case Attribute::DereferenceableOrNull: llvm_unreachable("dereferenceable_or_null attribute not supported in raw " "format"); break; case Attribute::ArgMemOnly: llvm_unreachable("argmemonly attribute not supported in raw format"); break; case Attribute::AllocSize: llvm_unreachable("allocsize not supported in raw format"); break; } llvm_unreachable("Unsupported attribute type"); } static void addRawAttributeValue(AttrBuilder &B, uint64_t Val) { if (!Val) return; for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; I = Attribute::AttrKind(I + 1)) { if (I == Attribute::Dereferenceable || I == Attribute::DereferenceableOrNull || I == Attribute::ArgMemOnly || I == Attribute::AllocSize) continue; if (uint64_t A = (Val & getRawAttributeMask(I))) { if (I == Attribute::Alignment) B.addAlignmentAttr(1ULL << ((A >> 16) - 1)); else if (I == Attribute::StackAlignment) B.addStackAlignmentAttr(1ULL << ((A >> 26)-1)); else B.addAttribute(I); } } } /// \brief This fills an AttrBuilder object with the LLVM attributes that have /// been decoded from the given integer. This function must stay in sync with /// 'encodeLLVMAttributesForBitcode'. static void decodeLLVMAttributesForBitcode(AttrBuilder &B, uint64_t EncodedAttrs) { // FIXME: Remove in 4.0. // The alignment is stored as a 16-bit raw value from bits 31--16. We shift // the bits above 31 down by 11 bits. unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; IGC_ASSERT((!Alignment || isPowerOf2_32(Alignment)) && "Alignment must be a power of two."); if (Alignment) B.addAlignmentAttr(Alignment); addRawAttributeValue(B, ((EncodedAttrs & (0xfffffULL << 32)) >> 11) | (EncodedAttrs & 0xffff)); } Error BitcodeReader::parseAttributeBlock() { if (Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID)) return error("Invalid record"); if (!MAttributes.empty()) return error("Invalid multiple blocks"); SmallVector Record; SmallVector Attrs; // Read all the records. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_CODE_ENTRY_OLD: { // ENTRY: [paramidx0, attr0, ...] // FIXME: Remove in 4.0. if (Record.size() & 1) return error("Invalid record"); for (unsigned i = 0, e = Record.size(); i != e; i += 2) { AttrBuilder B; decodeLLVMAttributesForBitcode(B, Record[i+1]); Attrs.push_back(AttributeSet::get(Context, Record[i], B)); } MAttributes.push_back(AttributeSet::get(Context, Attrs)); Attrs.clear(); break; } case bitc::PARAMATTR_CODE_ENTRY: { // ENTRY: [attrgrp0, attrgrp1, ...] for (unsigned i = 0, e = Record.size(); i != e; ++i) Attrs.push_back(MAttributeGroups[Record[i]]); MAttributes.push_back(AttributeSet::get(Context, Attrs)); Attrs.clear(); break; } } } } // Returns Attribute::None on unrecognized codes. static Attribute::AttrKind getAttrFromCode(uint64_t Code) { switch (Code) { default: return Attribute::None; case bitc::ATTR_KIND_ALIGNMENT: return Attribute::Alignment; case bitc::ATTR_KIND_ALWAYS_INLINE: return Attribute::AlwaysInline; case bitc::ATTR_KIND_ARGMEMONLY: return Attribute::ArgMemOnly; case bitc::ATTR_KIND_BUILTIN: return Attribute::Builtin; case bitc::ATTR_KIND_BY_VAL: return Attribute::ByVal; case bitc::ATTR_KIND_IN_ALLOCA: return Attribute::InAlloca; case bitc::ATTR_KIND_COLD: return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: return Attribute::InaccessibleMemOnly; case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: return Attribute::InaccessibleMemOrArgMemOnly; case bitc::ATTR_KIND_INLINE_HINT: return Attribute::InlineHint; case bitc::ATTR_KIND_IN_REG: return Attribute::InReg; case bitc::ATTR_KIND_JUMP_TABLE: return Attribute::JumpTable; case bitc::ATTR_KIND_MIN_SIZE: return Attribute::MinSize; case bitc::ATTR_KIND_NAKED: return Attribute::Naked; case bitc::ATTR_KIND_NEST: return Attribute::Nest; case bitc::ATTR_KIND_NO_ALIAS: return Attribute::NoAlias; case bitc::ATTR_KIND_NO_BUILTIN: return Attribute::NoBuiltin; case bitc::ATTR_KIND_NO_CAPTURE: return Attribute::NoCapture; case bitc::ATTR_KIND_NO_DUPLICATE: return Attribute::NoDuplicate; case bitc::ATTR_KIND_NO_IMPLICIT_FLOAT: return Attribute::NoImplicitFloat; case bitc::ATTR_KIND_NO_INLINE: return Attribute::NoInline; case bitc::ATTR_KIND_NO_RECURSE: return Attribute::NoRecurse; case bitc::ATTR_KIND_NON_LAZY_BIND: return Attribute::NonLazyBind; case bitc::ATTR_KIND_NON_NULL: return Attribute::NonNull; case bitc::ATTR_KIND_DEREFERENCEABLE: return Attribute::Dereferenceable; case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: return Attribute::DereferenceableOrNull; case bitc::ATTR_KIND_ALLOC_SIZE: return Attribute::AllocSize; case bitc::ATTR_KIND_NO_RED_ZONE: return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: return Attribute::NoReturn; case bitc::ATTR_KIND_NO_UNWIND: return Attribute::NoUnwind; case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: return Attribute::OptimizeForSize; case bitc::ATTR_KIND_OPTIMIZE_NONE: return Attribute::OptimizeNone; case bitc::ATTR_KIND_READ_NONE: return Attribute::ReadNone; case bitc::ATTR_KIND_READ_ONLY: return Attribute::ReadOnly; case bitc::ATTR_KIND_RETURNED: return Attribute::Returned; case bitc::ATTR_KIND_RETURNS_TWICE: return Attribute::ReturnsTwice; case bitc::ATTR_KIND_S_EXT: return Attribute::SExt; case bitc::ATTR_KIND_STACK_ALIGNMENT: return Attribute::StackAlignment; case bitc::ATTR_KIND_STACK_PROTECT: return Attribute::StackProtect; case bitc::ATTR_KIND_STACK_PROTECT_REQ: return Attribute::StackProtectReq; case bitc::ATTR_KIND_STACK_PROTECT_STRONG: return Attribute::StackProtectStrong; case bitc::ATTR_KIND_SAFESTACK: return Attribute::SafeStack; case bitc::ATTR_KIND_STRUCT_RET: return Attribute::StructRet; case bitc::ATTR_KIND_SANITIZE_ADDRESS: return Attribute::SanitizeAddress; case bitc::ATTR_KIND_SANITIZE_THREAD: return Attribute::SanitizeThread; case bitc::ATTR_KIND_SANITIZE_MEMORY: return Attribute::SanitizeMemory; case bitc::ATTR_KIND_SWIFT_ERROR: return Attribute::SwiftError; case bitc::ATTR_KIND_SWIFT_SELF: return Attribute::SwiftSelf; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; case bitc::ATTR_KIND_WRITEONLY: return Attribute::WriteOnly; case bitc::ATTR_KIND_Z_EXT: return Attribute::ZExt; } } Error BitcodeReader::parseAlignmentValue(uint64_t Exponent, unsigned &Alignment) { // Note: Alignment in bitcode files is incremented by 1, so that zero // can be used for default alignment. if (Exponent > Value::MaxAlignmentExponent + 1) return error("Invalid alignment value"); Alignment = (1 << static_cast(Exponent)) >> 1; return Error::success(); } Error BitcodeReader::parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind) { *Kind = getAttrFromCode(Code); if (*Kind == Attribute::None) return error("Unknown attribute kind (" + Twine(Code) + ")"); return Error::success(); } Error BitcodeReader::parseAttributeGroupBlock() { if (Stream.EnterSubBlock(bitc::PARAMATTR_GROUP_BLOCK_ID)) return error("Invalid record"); if (!MAttributeGroups.empty()) return error("Invalid multiple blocks"); SmallVector Record; // Read all the records. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_GRP_CODE_ENTRY: { // ENTRY: [grpid, idx, a0, a1, ...] if (Record.size() < 3) return error("Invalid record"); uint64_t GrpID = Record[0]; uint64_t Idx = Record[1]; // Index of the object this attribute refers to. AttrBuilder B; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Record[i] == 0) { // Enum attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; B.addAttribute(Kind); } else if (Record[i] == 1) { // Integer attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; if (Kind == Attribute::Alignment) B.addAlignmentAttr(Record[++i]); else if (Kind == Attribute::StackAlignment) B.addStackAlignmentAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); else if (Kind == Attribute::DereferenceableOrNull) B.addDereferenceableOrNullAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); } else { // String attribute IGC_ASSERT((Record[i] == 3 || Record[i] == 4) && "Invalid attribute group entry"); bool HasValue = (Record[i++] == 4); SmallString<64> KindStr; SmallString<64> ValStr; while (Record[i] != 0 && i != e) KindStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Kind string not null terminated"); if (HasValue) { // Has a value associated with it. ++i; // Skip the '0' that terminates the "kind" string. while (Record[i] != 0 && i != e) ValStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Value string not null terminated"); } B.addAttribute(KindStr.str(), ValStr.str()); } } MAttributeGroups[GrpID] = AttributeSet::get(Context, Idx, B); break; } } } } Error BitcodeReader::parseTypeTable() { if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW)) return error("Invalid record"); return parseTypeTableBody(); } Error BitcodeReader::parseTypeTableBody() { if (!TypeList.empty()) return error("Invalid multiple blocks"); SmallVector Record; unsigned NumRecords = 0; SmallString<64> TypeName; // Read all the records for this type table. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NumRecords != TypeList.size()) return error("Malformed block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *ResultTy = nullptr; switch (Stream.readRecord(Entry.ID, Record)) { default: return error("Invalid value"); case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] // TYPE_CODE_NUMENTRY contains a count of the number of types in the // type list. This allows us to reserve space. if (Record.size() < 1) return error("Invalid record"); TypeList.resize(Record[0]); continue; case bitc::TYPE_CODE_VOID: // VOID ResultTy = Type::getVoidTy(Context); break; case bitc::TYPE_CODE_HALF: // HALF ResultTy = Type::getHalfTy(Context); break; case bitc::TYPE_CODE_FLOAT: // FLOAT ResultTy = Type::getFloatTy(Context); break; case bitc::TYPE_CODE_DOUBLE: // DOUBLE ResultTy = Type::getDoubleTy(Context); break; case bitc::TYPE_CODE_X86_FP80: // X86_FP80 ResultTy = Type::getX86_FP80Ty(Context); break; case bitc::TYPE_CODE_FP128: // FP128 ResultTy = Type::getFP128Ty(Context); break; case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 ResultTy = Type::getPPC_FP128Ty(Context); break; case bitc::TYPE_CODE_LABEL: // LABEL ResultTy = Type::getLabelTy(Context); break; case bitc::TYPE_CODE_METADATA: // METADATA ResultTy = Type::getMetadataTy(Context); break; case bitc::TYPE_CODE_X86_MMX: // X86_MMX ResultTy = Type::getX86_MMXTy(Context); break; case bitc::TYPE_CODE_TOKEN: // TOKEN ResultTy = Type::getTokenTy(Context); break; case bitc::TYPE_CODE_INTEGER: { // INTEGER: [width] if (Record.size() < 1) return error("Invalid record"); uint64_t NumBits = Record[0]; if (NumBits < IntegerType::MIN_INT_BITS || NumBits > IntegerType::MAX_INT_BITS) return error("Bitwidth for integer type out of range"); ResultTy = IntegerType::get(Context, NumBits); break; } case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or // [pointee type, address space] if (Record.size() < 1) return error("Invalid record"); unsigned AddressSpace = 0; if (Record.size() == 2) AddressSpace = Record[1]; ResultTy = getTypeByID(Record[0]); if (!ResultTy || !PointerType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = PointerType::get(ResultTy, AddressSpace); break; } case bitc::TYPE_CODE_FUNCTION_OLD: { // FIXME: attrid is dead, remove it in LLVM 4.0 // FUNCTION: [vararg, attrid, retty, paramty x N] if (Record.size() < 3) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 3, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) ArgTys.push_back(T); else break; } ResultTy = getTypeByID(Record[2]); if (!ResultTy || ArgTys.size() < Record.size()-3) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_FUNCTION: { // FUNCTION: [vararg, retty, paramty x N] if (Record.size() < 2) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) { if (!FunctionType::isValidArgumentType(T)) return error("Invalid function argument type"); ArgTys.push_back(T); } else break; } ResultTy = getTypeByID(Record[1]); if (!ResultTy || ArgTys.size() < Record.size()-2) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid type"); ResultTy = StructType::get(Context, EltTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N] if (convertToString(Record, 0, TypeName)) return error("Invalid record"); continue; case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid record"); Res->setBody(EltTys, Record[0]); ResultTy = Res; break; } case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: [] if (Record.size() != 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct with no body. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); ResultTy = Res; break; } case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !ArrayType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = ArrayType::get(ResultTy, Record[0]); break; case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); if (Record[0] == 0) return error("Invalid vector length"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !StructType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = VectorType::get(ResultTy, Record[0]); break; } if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); if (TypeList[NumRecords]) return error( "Invalid TYPE table: Only named structs can be forward referenced"); IGC_ASSERT(ResultTy && "Didn't read a type?"); TypeList[NumRecords++] = ResultTy; } } Error BitcodeReader::parseOperandBundleTags() { if (Stream.EnterSubBlock(bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID)) return error("Invalid record"); if (!BundleTags.empty()) return error("Invalid multiple blocks"); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Tags are implicitly mapped to integers by their order. if (Stream.readRecord(Entry.ID, Record) != bitc::OPERAND_BUNDLE_TAG) return error("Invalid record"); // OPERAND_BUNDLE_TAG: [strchr x N] BundleTags.emplace_back(); if (convertToString(Record, 0, BundleTags.back())) return error("Invalid record"); Record.clear(); } } /// Associate a value with its name from the given index in the provided record. Expected BitcodeReader::recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT) { SmallString<128> ValueName; if (convertToString(Record, NameIndex, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; if (ValueID >= ValueList.size() || !ValueList[ValueID]) return error("Invalid record"); Value *V = ValueList[ValueID]; StringRef NameStr(ValueName.data(), ValueName.size()); if (NameStr.find_first_of(0) != StringRef::npos) return error("Invalid value name"); V->setName(NameStr); auto *GO = dyn_cast(V); if (GO) { if (GO->getComdat() == reinterpret_cast(1)) { if (TT.isOSBinFormatMachO()) GO->setComdat(nullptr); else GO->setComdat(TheModule->getOrInsertComdat(V->getName())); } } return V; } /// Helper to note and return the current location, and jump to the given /// offset. static uint64_t jumpToValueSymbolTable(uint64_t Offset, BitstreamCursor &Stream) { // Save the current parsing location so we can jump back at the end // of the VST read. uint64_t CurrentBit = Stream.GetCurrentBitNo(); Stream.JumpToBit(Offset * 32); #ifndef NDEBUG // Do some checking if we are in debug mode. BitstreamEntry Entry = Stream.advance(); IGC_ASSERT(Entry.Kind == BitstreamEntry::SubBlock); IGC_ASSERT(Entry.ID == bitc::VALUE_SYMTAB_BLOCK_ID); #else // In NDEBUG mode ignore the output so we don't get an unused variable // warning. Stream.advance(); #endif return CurrentBit; } /// Parse the value symbol table at either the current parsing location or /// at the given bit offset if provided. Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) { uint64_t CurrentBit; // Pass in the Offset to distinguish between calling for the module-level // VST (where we want to jump to the VST offset) and the function-level // VST (where we don't). if (Offset > 0) CurrentBit = jumpToValueSymbolTable(Offset, Stream); // Compute the delta between the bitcode indices in the VST (the word offset // to the word-aligned ENTER_SUBBLOCK for the function block, and that // expected by the lazy reader. The reader's EnterSubBlock expects to have // already read the ENTER_SUBBLOCK code (size getAbbrevIDWidth) and BlockID // (size BlockIDWidth). Note that we access the stream's AbbrevID width here // just before entering the VST subblock because: 1) the EnterSubBlock // changes the AbbrevID width; 2) the VST block is nested within the same // outer MODULE_BLOCK as the FUNCTION_BLOCKs and therefore have the same // AbbrevID width before calling EnterSubBlock; and 3) when we want to // jump to the FUNCTION_BLOCK using this offset later, we don't want // to rely on the stream's AbbrevID width being that of the MODULE_BLOCK. unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; Triple TT(TheModule->getTargetTriple()); // Read all the records for this value table. SmallString<128> ValueName; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (Offset > 0) Stream.JumpToBit(CurrentBit); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: unknown type. break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] Expected ValOrErr = recordValue(Record, 1, TT); if (Error Err = ValOrErr.takeError()) return Err; ValOrErr.get(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] Expected ValOrErr = recordValue(Record, 2, TT); if (Error Err = ValOrErr.takeError()) return Err; Value *V = ValOrErr.get(); auto *GO = dyn_cast(V); if (!GO) { // If this is an alias, need to get the actual Function object // it aliases, in order to set up the DeferredFunctionInfo entry below. auto *GA = dyn_cast(V); if (GA) GO = GA->getBaseObject(); IGC_ASSERT(GO); } // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. uint64_t FuncWordOffset = Record[1] - 1; Function *F = dyn_cast(GO); IGC_ASSERT(F); uint64_t FuncBitOffset = FuncWordOffset * 32; DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta; // Set the LastFunctionBlockBit to point to the last function block. // Later when parsing is resumed after function materialization, // we can simply skip that last function block. if (FuncBitOffset > LastFunctionBlockBit) LastFunctionBlockBit = FuncBitOffset; break; } case bitc::VST_CODE_BBENTRY: { if (convertToString(Record, 1, ValueName)) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[0]); if (!BB) return error("Invalid record"); BB->setName(StringRef(ValueName.data(), ValueName.size())); ValueName.clear(); break; } } } } /// Decode a signed value stored with the sign bit in the LSB for dense VBR /// encoding. uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) { if ((V & 1) == 0) return V >> 1; if (V != 1) return -(V >> 1); // There is no such thing as -0 with integers. "-0" really means MININT. return 1ULL << 63; } /// Resolve all of the initializers for global values and aliases that we can. Error BitcodeReader::resolveGlobalAndIndirectSymbolInits() { std::vector > GlobalInitWorklist; std::vector > IndirectSymbolInitWorklist; std::vector > FunctionPrefixWorklist; std::vector > FunctionPrologueWorklist; std::vector > FunctionPersonalityFnWorklist; GlobalInitWorklist.swap(GlobalInits); IndirectSymbolInitWorklist.swap(IndirectSymbolInits); FunctionPrefixWorklist.swap(FunctionPrefixes); FunctionPrologueWorklist.swap(FunctionPrologues); FunctionPersonalityFnWorklist.swap(FunctionPersonalityFns); while (!GlobalInitWorklist.empty()) { unsigned ValID = GlobalInitWorklist.back().second; if (ValID >= ValueList.size()) { // Not ready to resolve this yet, it requires something later in the file. GlobalInits.push_back(GlobalInitWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) GlobalInitWorklist.back().first->setInitializer(C); else return error("Expected a constant"); } GlobalInitWorklist.pop_back(); } while (!IndirectSymbolInitWorklist.empty()) { unsigned ValID = IndirectSymbolInitWorklist.back().second; if (ValID >= ValueList.size()) { IndirectSymbolInits.push_back(IndirectSymbolInitWorklist.back()); } else { Constant *C = dyn_cast_or_null(ValueList[ValID]); if (!C) return error("Expected a constant"); GlobalIndirectSymbol *GIS = IndirectSymbolInitWorklist.back().first; if (isa(GIS) && C->getType() != GIS->getType()) return error("Alias and aliasee types don't match"); GIS->setIndirectSymbol(C); } IndirectSymbolInitWorklist.pop_back(); } while (!FunctionPrefixWorklist.empty()) { unsigned ValID = FunctionPrefixWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrefixes.push_back(FunctionPrefixWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrefixWorklist.back().first->setPrefixData(C); else return error("Expected a constant"); } FunctionPrefixWorklist.pop_back(); } while (!FunctionPrologueWorklist.empty()) { unsigned ValID = FunctionPrologueWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrologues.push_back(FunctionPrologueWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrologueWorklist.back().first->setPrologueData(C); else return error("Expected a constant"); } FunctionPrologueWorklist.pop_back(); } while (!FunctionPersonalityFnWorklist.empty()) { unsigned ValID = FunctionPersonalityFnWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPersonalityFns.push_back(FunctionPersonalityFnWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPersonalityFnWorklist.back().first->setPersonalityFn(C); else return error("Expected a constant"); } FunctionPersonalityFnWorklist.pop_back(); } return Error::success(); } static APInt readWideAPInt(ArrayRef Vals, unsigned TypeBits) { SmallVector Words(Vals.size()); transform(Vals, Words.begin(), BitcodeReader::decodeSignRotatedValue); return APInt(TypeBits, Words); } Error BitcodeReader::parseConstants() { if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this value table. Type *CurTy = Type::getInt32Ty(Context); unsigned NextCstNo = ValueList.size(); while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NextCstNo != ValueList.size()) return error("Invalid constant reference"); // Once all the constants have been read, go through and resolve forward // references. ValueList.resolveConstantForwardRefs(); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *VoidType = Type::getVoidTy(Context); Value *V = nullptr; unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: unknown constant case bitc::CST_CODE_UNDEF: // UNDEF V = UndefValue::get(CurTy); break; case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid] if (Record.empty()) return error("Invalid record"); if (Record[0] >= TypeList.size() || !TypeList[Record[0]]) return error("Invalid record"); if (TypeList[Record[0]] == VoidType) return error("Invalid constant type"); CurTy = TypeList[Record[0]]; continue; // Skip the ValueList manipulation. case bitc::CST_CODE_NULL: // NULL V = Constant::getNullValue(CurTy); break; case bitc::CST_CODE_INTEGER: // INTEGER: [intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0])); break; case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); APInt VInt = readWideAPInt(Record, cast(CurTy)->getBitWidth()); V = ConstantInt::get(Context, VInt); break; } case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval] if (Record.empty()) return error("Invalid record"); if (CurTy->isHalfTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf(), APInt(16, (uint16_t)Record[0]))); else if (CurTy->isFloatTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle(), APInt(32, (uint32_t)Record[0]))); else if (CurTy->isDoubleTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble(), APInt(64, Record[0]))); else if (CurTy->isX86_FP80Ty()) { // Bits are not stored the same way as a normal i80 APInt, compensate. uint64_t Rearrange[2]; Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16); Rearrange[1] = Record[0] >> 48; V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended(), APInt(80, Rearrange))); } else if (CurTy->isFP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad(), APInt(128, Record))); else if (CurTy->isPPC_FP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble(), APInt(128, Record))); else V = UndefValue::get(CurTy); break; } case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number] if (Record.empty()) return error("Invalid record"); unsigned Size = Record.size(); SmallVector Elts; if (StructType *STy = dyn_cast(CurTy)) { for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); } else if (ArrayType *ATy = dyn_cast(CurTy)) { Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantArray::get(ATy, Elts); } else if (VectorType *VTy = dyn_cast(CurTy)) { Type *EltTy = VTy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantVector::get(Elts); } else { V = UndefValue::get(CurTy); } break; } case bitc::CST_CODE_STRING: // STRING: [values] case bitc::CST_CODE_CSTRING: { // CSTRING: [values] if (Record.empty()) return error("Invalid record"); SmallString<16> Elts(Record.begin(), Record.end()); V = ConstantDataArray::getString(Context, Elts, BitCode == bitc::CST_CODE_CSTRING); break; } case bitc::CST_CODE_DATA: {// DATA: [n x value] if (Record.empty()) return error("Invalid record"); Type *EltTy = cast(CurTy)->getElementType(); if (EltTy->isIntegerTy(8)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(16)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(32)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(64)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isHalfTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isFloatTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isDoubleTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else { return error("Invalid type for value"); } break; } case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[0], CurTy); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown binop. } else { Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy); unsigned Flags = 0; if (Record.size() >= 4) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoSignedWrap; if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoUnsignedWrap; } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[3] & (1 << bitc::PEO_EXACT)) Flags |= SDivOperator::IsExact; } } V = ConstantExpr::get(Opc, LHS, RHS, Flags); } break; } case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedCastOpcode(Record[0]); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown cast. } else { Type *OpTy = getTypeByID(Record[1]); if (!OpTy) return error("Invalid record"); Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy); V = upgradeBitCastExpr(Opc, Op, CurTy); if (!V) V = ConstantExpr::getCast(Opc, Op, CurTy); } break; } case bitc::CST_CODE_CE_INBOUNDS_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX: { // [ty, flags, n x // operands] unsigned OpNum = 0; Type *PointeeType = nullptr; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX || Record.size() % 2) PointeeType = getTypeByID(Record[OpNum++]); bool InBounds = false; Optional InRangeIndex; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX) { uint64_t Op = Record[OpNum++]; InBounds = Op & 1; InRangeIndex = Op >> 1; } else if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP) InBounds = true; SmallVector Elts; while (OpNum != Record.size()) { Type *ElTy = getTypeByID(Record[OpNum++]); if (!ElTy) return error("Invalid record"); Elts.push_back(ValueList.getConstantFwdRef(Record[OpNum++], ElTy)); } if (PointeeType && PointeeType != cast(Elts[0]->getType()->getScalarType()) ->getElementType()) return error("Explicit gep operator type does not match pointee type " "of pointer operand"); if (Elts.size() < 1) return error("Invalid gep with no operands"); ArrayRef Indices(Elts.begin() + 1, Elts.end()); V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices, InBounds, InRangeIndex); break; } case bitc::CST_CODE_CE_SELECT: { // CE_SELECT: [opval#, opval#, opval#] if (Record.size() < 3) return error("Invalid record"); Type *SelectorTy = Type::getInt1Ty(Context); // The selector might be an i1 or an // Get the type from the ValueList before getting a forward ref. if (VectorType *VTy = dyn_cast(CurTy)) if (Value *V = ValueList[Record[0]]) if (SelectorTy != V->getType()) SelectorTy = VectorType::get(SelectorTy, VTy->getNumElements()); V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0], SelectorTy), ValueList.getConstantFwdRef(Record[1],CurTy), ValueList.getConstantFwdRef(Record[2],CurTy)); break; } case bitc::CST_CODE_CE_EXTRACTELT : { // CE_EXTRACTELT: [opty, opval, opty, opval] if (Record.size() < 3) return error("Invalid record"); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op1 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op1) return error("Invalid record"); V = ConstantExpr::getExtractElement(Op0, Op1); break; } case bitc::CST_CODE_CE_INSERTELT : { // CE_INSERTELT: [opval, opval, opty, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy->getElementType()); Constant *Op2 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op2 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op2) return error("Invalid record"); V = ConstantExpr::getInsertElement(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), OpTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval] VectorType *RTy = dyn_cast(CurTy); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (Record.size() < 4 || !RTy || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), RTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred] if (Record.size() < 4) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); if (OpTy->isFPOrFPVectorTy()) V = ConstantExpr::getFCmp(Record[3], Op0, Op1); else V = ConstantExpr::getICmp(Record[3], Op0, Op1); break; } // This maintains backward compatibility, pre-asm dialect keywords. // FIXME: Remove with the 4.0 release. case bitc::CST_CODE_INLINEASM_OLD: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = Record[0] >> 1; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; PointerType *PTy = cast(CurTy); V = InlineAsm::get(cast(PTy->getElementType()), AsmStr, ConstrStr, HasSideEffects, IsAlignStack); break; } // This version adds support for the asm dialect keywords (e.g., // inteldialect). case bitc::CST_CODE_INLINEASM: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = (Record[0] >> 1) & 1; unsigned AsmDialect = Record[0] >> 2; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; PointerType *PTy = cast(CurTy); V = InlineAsm::get(cast(PTy->getElementType()), AsmStr, ConstrStr, HasSideEffects, IsAlignStack, InlineAsm::AsmDialect(AsmDialect)); break; } case bitc::CST_CODE_BLOCKADDRESS:{ if (Record.size() < 3) return error("Invalid record"); Type *FnTy = getTypeByID(Record[0]); if (!FnTy) return error("Invalid record"); Function *Fn = dyn_cast_or_null(ValueList.getConstantFwdRef(Record[1],FnTy)); if (!Fn) return error("Invalid record"); // If the function is already parsed we can insert the block address right // away. BasicBlock *BB; unsigned BBID = Record[2]; if (!BBID) // Invalid reference to entry block. return error("Invalid ID"); if (!Fn->empty()) { Function::iterator BBI = Fn->begin(), BBE = Fn->end(); for (size_t I = 0, E = BBID; I != E; ++I) { if (BBI == BBE) return error("Invalid ID"); ++BBI; } BB = &*BBI; } else { // Otherwise insert a placeholder and remember it so it can be inserted // when the function is parsed. auto &FwdBBs = BasicBlockFwdRefs[Fn]; if (FwdBBs.empty()) BasicBlockFwdRefQueue.push_back(Fn); if (FwdBBs.size() < BBID + 1) FwdBBs.resize(BBID + 1); if (!FwdBBs[BBID]) FwdBBs[BBID] = BasicBlock::Create(Context); BB = FwdBBs[BBID]; } V = BlockAddress::get(Fn, BB); break; } } ValueList.assignValue(V, NextCstNo); ++NextCstNo; } } Error BitcodeReader::parseUseLists() { if (Stream.EnterSubBlock(bitc::USELIST_BLOCK_ID)) return error("Invalid record"); // Read all the records. SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a use list record. Record.clear(); bool IsBB = false; switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: unknown type. break; case bitc::USELIST_CODE_BB: IsBB = true; LLVM_FALLTHROUGH; case bitc::USELIST_CODE_DEFAULT: { unsigned RecordLength = Record.size(); if (RecordLength < 3) // Records should have at least an ID and two indexes. return error("Invalid record"); unsigned ID = Record.back(); Record.pop_back(); Value *V; if (IsBB) { IGC_ASSERT(ID < FunctionBBs.size() && "Basic block not found"); V = FunctionBBs[ID]; } else V = ValueList[ID]; unsigned NumUses = 0; SmallDenseMap Order; for (const Use &U : V->materialized_uses()) { if (++NumUses > Record.size()) break; Order[&U] = Record[NumUses - 1]; } if (Order.size() != Record.size() || NumUses > Record.size()) // Mismatches can happen if the functions are being materialized lazily // (out-of-order), or a value has been upgraded. break; V->sortUseList([&](const Use &L, const Use &R) { return Order.lookup(&L) < Order.lookup(&R); }); break; } } } } /// When we see the block for metadata, remember where it is and then skip it. /// This lets us lazily deserialize the metadata. Error BitcodeReader::rememberAndSkipMetadata() { // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); DeferredMetadataInfo.push_back(CurBit); // Skip over the block for now. if (Stream.SkipBlock()) return error("Invalid record"); return Error::success(); } Error BitcodeReader::materializeMetadata() { for (uint64_t BitPos : DeferredMetadataInfo) { // Move the bit stream to the saved position. Stream.JumpToBit(BitPos); if (Error Err = MDLoader->parseModuleMetadata()) return Err; } DeferredMetadataInfo.clear(); return Error::success(); } void BitcodeReader::setStripDebugInfo() { StripDebugInfo = true; } /// When we see the block for a function body, remember where it is and then /// skip it. This lets us lazily deserialize the functions. Error BitcodeReader::rememberAndSkipFunctionBody() { // Get the function we are talking about. if (FunctionsWithBodies.empty()) return error("Insufficient function protos"); Function *Fn = FunctionsWithBodies.back(); FunctionsWithBodies.pop_back(); // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); IGC_ASSERT( (DeferredFunctionInfo[Fn] == 0 || DeferredFunctionInfo[Fn] == CurBit) && "Mismatch between VST and scanned function offsets"); DeferredFunctionInfo[Fn] = CurBit; // Skip over the function block for now. if (Stream.SkipBlock()) return error("Invalid record"); return Error::success(); } Error BitcodeReader::globalCleanup() { // Patch the initializers for globals and aliases up. if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; if (!GlobalInits.empty() || !IndirectSymbolInits.empty()) return error("Malformed global initializer set"); // Look for intrinsic functions which need to be upgraded at some point for (Function &F : *TheModule) { Function *NewFn; if (UpgradeIntrinsicFunction(&F, NewFn)) UpgradedIntrinsics[&F] = NewFn; else if (auto Remangled = Intrinsic::remangleIntrinsicFunction(&F)) // Some types could be renamed during loading if several modules are // loaded in the same LLVMContext (LTO scenario). In this case we should // remangle intrinsics names as well. RemangledIntrinsics[&F] = Remangled.getValue(); } // Look for global variables which need to be renamed. for (GlobalVariable &GV : TheModule->globals()) UpgradeGlobalVariable(&GV); // Force deallocation of memory for these vectors to favor the client that // want lazy deserialization. std::vector >().swap(GlobalInits); std::vector >().swap( IndirectSymbolInits); return Error::success(); } /// Support for lazy parsing of function bodies. This is required if we /// either have an old bitcode file without a VST forward declaration record, /// or if we have an anonymous function being materialized, since anonymous /// functions do not have a name and are therefore not in the VST. Error BitcodeReader::rememberAndSkipFunctionBodies() { Stream.JumpToBit(NextUnreadBit); if (Stream.AtEndOfStream()) return error("Could not find function in stream"); if (!SeenFirstFunctionBody) return error("Trying to materialize functions before seeing function blocks"); // An old bitcode file with the symbol table at the end would have // finished the parse greedily. IGC_ASSERT(SeenValueSymbolTable); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { default: return error("Expect SubBlock"); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: return error("Expect function block"); case bitc::FUNCTION_BLOCK_ID: if (Error Err = rememberAndSkipFunctionBody()) return Err; NextUnreadBit = Stream.GetCurrentBitNo(); return Error::success(); } } } } bool BitcodeReaderBase::readBlockInfo() { Optional NewBlockInfo = Stream.ReadBlockInfoBlock(); if (!NewBlockInfo) return true; BlockInfo = std::move(*NewBlockInfo); return false; } Error BitcodeReader::parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata) { if (ResumeBit) Stream.JumpToBit(ResumeBit); else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; std::vector SectionTable; std::vector GCTable; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return globalCleanup(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::BLOCKINFO_BLOCK_ID: if (readBlockInfo()) return error("Malformed block"); break; case bitc::PARAMATTR_BLOCK_ID: if (Error Err = parseAttributeBlock()) return Err; break; case bitc::PARAMATTR_GROUP_BLOCK_ID: if (Error Err = parseAttributeGroupBlock()) return Err; break; case bitc::TYPE_BLOCK_ID_NEW: if (Error Err = parseTypeTable()) return Err; break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (!SeenValueSymbolTable) { // Either this is an old form VST without function index and an // associated VST forward declaration record (which would have caused // the VST to be jumped to and parsed before it was encountered // normally in the stream), or there were no function blocks to // trigger an earlier parsing of the VST. IGC_ASSERT(VSTOffset == 0 || FunctionsWithBodies.empty()); if (Error Err = parseValueSymbolTable()) return Err; SeenValueSymbolTable = true; } else { // We must have had a VST forward declaration record, which caused // the parser to jump to and parse the VST earlier. IGC_ASSERT(VSTOffset > 0); if (Stream.SkipBlock()) return error("Invalid record"); } break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; break; case bitc::METADATA_BLOCK_ID: if (ShouldLazyLoadMetadata) { if (Error Err = rememberAndSkipMetadata()) return Err; break; } IGC_ASSERT(DeferredMetadataInfo.empty() && "Unexpected deferred metadata"); if (Error Err = MDLoader->parseModuleMetadata()) return Err; break; case bitc::METADATA_KIND_BLOCK_ID: if (Error Err = MDLoader->parseMetadataKinds()) return Err; break; case bitc::FUNCTION_BLOCK_ID: // If this is the first function body we've seen, reverse the // FunctionsWithBodies list. if (!SeenFirstFunctionBody) { std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end()); if (Error Err = globalCleanup()) return Err; SeenFirstFunctionBody = true; } if (VSTOffset > 0) { // If we have a VST forward declaration record, make sure we // parse the VST now if we haven't already. It is needed to // set up the DeferredFunctionInfo vector for lazy reading. if (!SeenValueSymbolTable) { if (Error Err = BitcodeReader::parseValueSymbolTable(VSTOffset)) return Err; SeenValueSymbolTable = true; // Fall through so that we record the NextUnreadBit below. // This is necessary in case we have an anonymous function that // is later materialized. Since it will not have a VST entry we // need to fall back to the lazy parse to find its offset. } else { // If we have a VST forward declaration record, but have already // parsed the VST (just above, when the first function body was // encountered here), then we are resuming the parse after // materializing functions. The ResumeBit points to the // start of the last function block recorded in the // DeferredFunctionInfo map. Skip it. if (Stream.SkipBlock()) return error("Invalid record"); continue; } } // Support older bitcode files that did not have the function // index in the VST, nor a VST forward declaration record, as // well as anonymous functions that do not have VST entries. // Build the DeferredFunctionInfo vector on the fly. if (Error Err = rememberAndSkipFunctionBody()) return Err; // Suspend parsing when we reach the function bodies. Subsequent // materialization calls will resume it when necessary. If the bitcode // file is old, the symbol table will be at the end instead and will not // have been seen yet. In this case, just finish the parse now. if (SeenValueSymbolTable) { NextUnreadBit = Stream.GetCurrentBitNo(); // After the VST has been parsed, we need to make sure intrinsic name // are auto-upgraded. return globalCleanup(); } break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: if (Error Err = parseOperandBundleTags()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { // VERSION: [version#] if (Record.size() < 1) return error("Invalid record"); // Only version #0 and #1 are supported so far. unsigned module_version = Record[0]; switch (module_version) { default: return error("Invalid value"); case 0: UseRelativeIDs = false; break; case 1: UseRelativeIDs = true; break; } break; } case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setTargetTriple(S); break; } case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); size_t index = S.find("-a64:64:64"); if (index != std::string::npos) S.replace(index, 10, ""); TheModule->setDataLayout(S); break; } case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setModuleInlineAsm(S); break; } case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N] // FIXME: Remove in 4.0. std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Ignore value. break; } case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); SectionTable.push_back(S); break; } case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); GCTable.push_back(S); break; } case bitc::MODULE_CODE_COMDAT: { // COMDAT: [selection_kind, name] if (Record.size() < 2) return error("Invalid record"); Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]); unsigned ComdatNameSize = Record[1]; std::string ComdatName; ComdatName.reserve(ComdatNameSize); for (unsigned i = 0; i != ComdatNameSize; ++i) ComdatName += (char)Record[2 + i]; Comdat *C = TheModule->getOrInsertComdat(ComdatName); C->setSelectionKind(SK); ComdatList.push_back(C); break; } // GLOBALVAR: [pointer type, isconst, initid, // linkage, alignment, section, visibility, threadlocal, // unnamed_addr, externally_initialized, dllstorageclass, // comdat] case bitc::MODULE_CODE_GLOBALVAR: { if (Record.size() < 6) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); bool isConstant = Record[1] & 1; bool explicitType = Record[1] & 2; unsigned AddressSpace; if (explicitType) { AddressSpace = Record[1] >> 2; } else { if (!Ty->isPointerTy()) return error("Invalid type for value"); AddressSpace = cast(Ty)->getAddressSpace(); Ty = cast(Ty)->getElementType(); } uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); unsigned Alignment; if (Error Err = parseAlignmentValue(Record[4], Alignment)) return Err; std::string Section; if (Record[5]) { if (Record[5]-1 >= SectionTable.size()) return error("Invalid ID"); Section = SectionTable[Record[5]-1]; } GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; // Local linkage must have default visibility. if (Record.size() > 6 && !GlobalValue::isLocalLinkage(Linkage)) // FIXME: Change to an error if non-default in 4.0. Visibility = getDecodedVisibility(Record[6]); GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; if (Record.size() > 7) TLM = getDecodedThreadLocalMode(Record[7]); GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 8) UnnamedAddr = getDecodedUnnamedAddrType(Record[8]); bool ExternallyInitialized = false; if (Record.size() > 9) ExternallyInitialized = Record[9]; GlobalVariable *NewGV = new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, "", nullptr, TLM, AddressSpace, ExternallyInitialized); NewGV->setAlignment(Alignment); if (!Section.empty()) NewGV->setSection(Section); NewGV->setVisibility(Visibility); NewGV->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10) NewGV->setDLLStorageClass(getDecodedDLLStorageClass(Record[10])); else upgradeDLLImportExportLinkage(NewGV, RawLinkage); ValueList.push_back(NewGV); // Remember which value to use for the global initializer. if (unsigned InitID = Record[2]) GlobalInits.push_back(std::make_pair(NewGV, InitID-1)); if (Record.size() > 11) { if (unsigned ComdatID = Record[11]) { if (ComdatID > ComdatList.size()) return error("Invalid global variable comdat ID"); NewGV->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { NewGV->setComdat(reinterpret_cast(1)); } break; } // FUNCTION: [type, callingconv, isproto, linkage, paramattr, // alignment, section, visibility, gc, unnamed_addr, // prologuedata, dllstorageclass, comdat, prefixdata] case bitc::MODULE_CODE_FUNCTION: { if (Record.size() < 8) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); if (auto *PTy = dyn_cast(Ty)) Ty = PTy->getElementType(); auto *FTy = dyn_cast(Ty); if (!FTy) return error("Invalid type for value"); auto CC = static_cast(Record[1]); if (CC & ~CallingConv::MaxID) return error("Invalid calling convention ID"); Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage, "", TheModule); Func->setCallingConv(CC); bool isProto = Record[2]; uint64_t RawLinkage = Record[3]; Func->setLinkage(getDecodedLinkage(RawLinkage)); Func->setAttributes(getAttributes(Record[4])); unsigned Alignment; if (Error Err = parseAlignmentValue(Record[5], Alignment)) return Err; Func->setAlignment(Alignment); if (Record[6]) { if (Record[6]-1 >= SectionTable.size()) return error("Invalid ID"); Func->setSection(SectionTable[Record[6]-1]); } // Local linkage must have default visibility. if (!Func->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. Func->setVisibility(getDecodedVisibility(Record[7])); if (Record.size() > 8 && Record[8]) { if (Record[8]-1 >= GCTable.size()) return error("Invalid ID"); Func->setGC(GCTable[Record[8] - 1]); } GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 9) UnnamedAddr = getDecodedUnnamedAddrType(Record[9]); Func->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10 && Record[10] != 0) FunctionPrologues.push_back(std::make_pair(Func, Record[10]-1)); if (Record.size() > 11) Func->setDLLStorageClass(getDecodedDLLStorageClass(Record[11])); else upgradeDLLImportExportLinkage(Func, RawLinkage); if (Record.size() > 12) { if (unsigned ComdatID = Record[12]) { if (ComdatID > ComdatList.size()) return error("Invalid function comdat ID"); Func->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { Func->setComdat(reinterpret_cast(1)); } if (Record.size() > 13 && Record[13] != 0) FunctionPrefixes.push_back(std::make_pair(Func, Record[13]-1)); if (Record.size() > 14 && Record[14] != 0) FunctionPersonalityFns.push_back(std::make_pair(Func, Record[14] - 1)); ValueList.push_back(Func); // If this is a function with a body, remember the prototype we are // creating now, so that we can match up the body with them later. if (!isProto) { Func->setIsMaterializable(true); FunctionsWithBodies.push_back(Func); DeferredFunctionInfo[Func] = 0; } break; } // ALIAS: [alias type, addrspace, aliasee val#, linkage] // ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, dllstorageclass] // IFUNC: [alias type, addrspace, aliasee val#, linkage, visibility, dllstorageclass] case bitc::MODULE_CODE_IFUNC: case bitc::MODULE_CODE_ALIAS: case bitc::MODULE_CODE_ALIAS_OLD: { bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD; if (Record.size() < (3 + (unsigned)NewRecord)) return error("Invalid record"); unsigned OpNum = 0; Type *Ty = getTypeByID(Record[OpNum++]); if (!Ty) return error("Invalid record"); unsigned AddrSpace; if (!NewRecord) { auto *PTy = dyn_cast(Ty); if (!PTy) return error("Invalid type for value"); Ty = PTy->getElementType(); AddrSpace = PTy->getAddressSpace(); } else { AddrSpace = Record[OpNum++]; } auto Val = Record[OpNum++]; auto Linkage = Record[OpNum++]; GlobalIndirectSymbol *NewGA; if (BitCode == bitc::MODULE_CODE_ALIAS || BitCode == bitc::MODULE_CODE_ALIAS_OLD) NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), "", TheModule); else NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), "", nullptr, TheModule); // Old bitcode files didn't have visibility field. // Local linkage must have default visibility. if (OpNum != Record.size()) { auto VisInd = OpNum++; if (!NewGA->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. NewGA->setVisibility(getDecodedVisibility(Record[VisInd])); } if (OpNum != Record.size()) NewGA->setDLLStorageClass(getDecodedDLLStorageClass(Record[OpNum++])); else upgradeDLLImportExportLinkage(NewGA, Linkage); if (OpNum != Record.size()) NewGA->setThreadLocalMode(getDecodedThreadLocalMode(Record[OpNum++])); if (OpNum != Record.size()) NewGA->setUnnamedAddr(getDecodedUnnamedAddrType(Record[OpNum++])); ValueList.push_back(NewGA); IndirectSymbolInits.push_back(std::make_pair(NewGA, Val)); break; } /// MODULE_CODE_PURGEVALS: [numvals] case bitc::MODULE_CODE_PURGEVALS: // Trim down the value list to the specified size. if (Record.size() < 1 || Record[0] > ValueList.size()) return error("Invalid record"); ValueList.shrinkTo(Record[0]); break; /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); TheModule->setSourceFileName(ValueName); break; } Record.clear(); } } Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata, bool IsImporting) { TheModule = M; MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting, [&](unsigned ID) { return getTypeByID(ID); }); return parseModule(0, ShouldLazyLoadMetadata); } Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) { if (!isa(PtrType)) return error("Load/Store operand is not a pointer type"); Type *ElemType = cast(PtrType)->getElementType(); if (ValType && ValType != ElemType) return error("Explicit load/store type does not match pointee " "type of pointer operand"); if (!PointerType::isLoadableOrStorableType(ElemType)) return error("Cannot load/store from pointer"); return Error::success(); } /// Lazily parse the specified function body block. Error BitcodeReader::parseFunctionBody(Function *F) { if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID)) return error("Invalid record"); // Unexpected unresolved metadata when parsing function. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: incoming forward references"); InstructionList.clear(); unsigned ModuleValueListSize = ValueList.size(); unsigned ModuleMDLoaderSize = MDLoader->size(); // Add all the function arguments to the value table. for (Argument &I : F->args()) ValueList.push_back(&I); unsigned NextValueNo = ValueList.size(); BasicBlock *CurBB = nullptr; unsigned CurBBNo = 0; DebugLoc LastLoc; auto getLastInstruction = [&]() -> Instruction * { if (CurBB && !CurBB->empty()) return &CurBB->back(); else if (CurBBNo && FunctionBBs[CurBBNo - 1] && !FunctionBBs[CurBBNo - 1]->empty()) return &FunctionBBs[CurBBNo - 1]->back(); return nullptr; }; std::vector OperandBundles; // Read all the records. SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: goto OutOfRecordLoop; case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; NextValueNo = ValueList.size(); break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (Error Err = parseValueSymbolTable()) return Err; break; case bitc::METADATA_ATTACHMENT_ID: if (Error Err = MDLoader->parseMetadataAttachment(*F, InstructionList)) return Err; break; case bitc::METADATA_BLOCK_ID: IGC_ASSERT(DeferredMetadataInfo.empty() && "Must read all module-level metadata before function-level"); if (Error Err = MDLoader->parseFunctionMetadata()) return Err; break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Instruction *I = nullptr; unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: reject return error("Invalid value"); case bitc::FUNC_CODE_DECLAREBLOCKS: { // DECLAREBLOCKS: [nblocks] if (Record.size() < 1 || Record[0] == 0) return error("Invalid record"); // Create all the basic blocks for the function. FunctionBBs.resize(Record[0]); // See if anything took the address of blocks in this function. auto BBFRI = BasicBlockFwdRefs.find(F); if (BBFRI == BasicBlockFwdRefs.end()) { for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i) FunctionBBs[i] = BasicBlock::Create(Context, "", F); } else { auto &BBRefs = BBFRI->second; // Check for invalid basic block references. if (BBRefs.size() > FunctionBBs.size()) return error("Invalid ID"); IGC_ASSERT(!BBRefs.empty() && "Unexpected empty array"); IGC_ASSERT(!BBRefs.front() && "Invalid reference to entry block"); for (unsigned I = 0, E = FunctionBBs.size(), RE = BBRefs.size(); I != E; ++I) if (I < RE && BBRefs[I]) { BBRefs[I]->insertInto(F); FunctionBBs[I] = BBRefs[I]; } else { FunctionBBs[I] = BasicBlock::Create(Context, "", F); } // Erase from the table. BasicBlockFwdRefs.erase(BBFRI); } CurBB = FunctionBBs[0]; continue; } case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN // This record indicates that the last instruction is at the same // location as the previous instruction with a location. I = getLastInstruction(); if (!I) return error("Invalid record"); I->setDebugLoc(LastLoc); I = nullptr; continue; case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia] I = getLastInstruction(); if (!I || Record.size() < 4) return error("Invalid record"); unsigned Line = Record[0], Col = Record[1]; unsigned ScopeID = Record[2], IAID = Record[3]; MDNode *Scope = nullptr, *IA = nullptr; if (ScopeID) { Scope = MDLoader->getMDNodeFwdRefOrNull(ScopeID - 1); if (!Scope) return error("Invalid record"); } if (IAID) { IA = MDLoader->getMDNodeFwdRefOrNull(IAID - 1); if (!IA) return error("Invalid record"); } LastLoc = DebugLoc::get(Line, Col, Scope, IA); I->setDebugLoc(LastLoc); I = nullptr; continue; } case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode] unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS) || OpNum+1 > Record.size()) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return error("Invalid record"); I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); InstructionList.push_back(I); if (OpNum < Record.size()) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) cast(I)->setHasNoSignedWrap(true); if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) cast(I)->setHasNoUnsignedWrap(true); } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } else if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } } break; } case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || OpNum+2 != Record.size()) return error("Invalid record"); Type *ResTy = getTypeByID(Record[OpNum]); int Opc = getDecodedCastOpcode(Record[OpNum + 1]); if (Opc == -1 || !ResTy) return error("Invalid record"); Instruction *Temp = nullptr; if ((I = upgradeBitCastInst(Opc, Op, ResTy, Temp))) { if (Temp) { InstructionList.push_back(Temp); CurBB->getInstList().push_back(Temp); } } else { auto CastOp = (Instruction::CastOps)Opc; if (!CastInst::castIsValid(CastOp, Op, ResTy)) return error("Invalid cast"); I = CastInst::Create(CastOp, Op, ResTy); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD: case bitc::FUNC_CODE_INST_GEP_OLD: case bitc::FUNC_CODE_INST_GEP: { // GEP: type, [n x operands] unsigned OpNum = 0; Type *Ty; bool InBounds; if (BitCode == bitc::FUNC_CODE_INST_GEP) { InBounds = Record[OpNum++]; Ty = getTypeByID(Record[OpNum++]); } else { InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD; Ty = nullptr; } Value *BasePtr; if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr)) return error("Invalid record"); if (!Ty) Ty = cast(BasePtr->getType()->getScalarType()) ->getElementType(); else if (Ty != cast(BasePtr->getType()->getScalarType()) ->getElementType()) return error( "Explicit gep type does not match pointee type of pointer operand"); SmallVector GEPIdx; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); GEPIdx.push_back(Op); } I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx); InstructionList.push_back(I); if (InBounds) cast(I)->setIsInBounds(true); break; } case bitc::FUNC_CODE_INST_EXTRACTVAL: { // EXTRACTVAL: [opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("EXTRACTVAL: Invalid instruction with 0 indices"); SmallVector EXTRACTVALIdx; Type *CurTy = Agg->getType(); for (; OpNum != RecSize; ++OpNum) { bool IsArray = CurTy->isArrayTy(); bool IsStruct = CurTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("EXTRACTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= CurTy->subtypes().size()) return error("EXTRACTVAL: Invalid struct index"); if (IsArray && Index >= CurTy->getArrayNumElements()) return error("EXTRACTVAL: Invalid array index"); EXTRACTVALIdx.push_back((unsigned)Index); if (IsStruct) CurTy = CurTy->subtypes()[Index]; else CurTy = CurTy->subtypes()[0]; } I = ExtractValueInst::Create(Agg, EXTRACTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTVAL: { // INSERTVAL: [opty, opval, opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) return error("Invalid record"); Value *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Val)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("INSERTVAL: Invalid instruction with 0 indices"); SmallVector INSERTVALIdx; Type *CurTy = Agg->getType(); for (; OpNum != RecSize; ++OpNum) { bool IsArray = CurTy->isArrayTy(); bool IsStruct = CurTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("INSERTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= CurTy->subtypes().size()) return error("INSERTVAL: Invalid struct index"); if (IsArray && Index >= CurTy->getArrayNumElements()) return error("INSERTVAL: Invalid array index"); INSERTVALIdx.push_back((unsigned)Index); if (IsStruct) CurTy = CurTy->subtypes()[Index]; else CurTy = CurTy->subtypes()[0]; } if (CurTy != Val->getType()) return error("Inserted value type doesn't match aggregate type"); I = InsertValueInst::Create(Agg, Val, INSERTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval] // obsolete form of select // handles select i1 ... in old bitcode unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || popValue(Record, OpNum, NextValueNo, Type::getInt1Ty(Context), Cond)) return error("Invalid record"); I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred] // new form of select // handles select i1 or select [N x i1] unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || getValueTypePair(Record, OpNum, NextValueNo, Cond)) return error("Invalid record"); // select condition can be either i1 or [N x i1] if (VectorType* vector_type = dyn_cast(Cond->getType())) { // expect if (vector_type->getElementType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } else { // expect i1 if (Cond->getType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval] unsigned OpNum = 0; Value *Vec, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); I = ExtractElementInst::Create(Vec, Idx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval] unsigned OpNum = 0; Value *Vec, *Elt, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); if (popValue(Record, OpNum, NextValueNo, cast(Vec->getType())->getElementType(), Elt) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); I = InsertElementInst::Create(Vec, Elt, Idx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval] unsigned OpNum = 0; Value *Vec1, *Vec2, *Mask; if (getValueTypePair(Record, OpNum, NextValueNo, Vec1) || popValue(Record, OpNum, NextValueNo, Vec1->getType(), Vec2)) return error("Invalid record"); if (getValueTypePair(Record, OpNum, NextValueNo, Mask)) return error("Invalid record"); if (!Vec1->getType()->isVectorTy() || !Vec2->getType()->isVectorTy()) return error("Invalid type for value"); I = new ShuffleVectorInst(Vec1, Vec2, Mask); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred] // Old form of ICmp/FCmp returning bool // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were // both legal on vectors but had different behaviour. case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred] // FCmp/ICmp returning bool or vector of bool unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS)) return error("Invalid record"); unsigned PredVal = Record[OpNum]; bool IsFP = LHS->getType()->isFPOrFPVectorTy(); FastMathFlags FMF; if (IsFP && Record.size() > OpNum+1) FMF = getDecodedFastMathFlags(Record[++OpNum]); if (OpNum+1 != Record.size()) return error("Invalid record"); if (LHS->getType()->isFPOrFPVectorTy()) I = new FCmpInst((FCmpInst::Predicate)PredVal, LHS, RHS); else I = new ICmpInst((ICmpInst::Predicate)PredVal, LHS, RHS); if (FMF.any()) I->setFastMathFlags(FMF); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval] { unsigned Size = Record.size(); if (Size == 0) { I = ReturnInst::Create(Context); InstructionList.push_back(I); break; } unsigned OpNum = 0; Value *Op = nullptr; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); if (OpNum != Record.size()) return error("Invalid record"); I = ReturnInst::Create(Context, Op); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#] if (Record.size() != 1 && Record.size() != 3) return error("Invalid record"); BasicBlock *TrueDest = getBasicBlock(Record[0]); if (!TrueDest) return error("Invalid record"); if (Record.size() == 1) { I = BranchInst::Create(TrueDest); InstructionList.push_back(I); } else { BasicBlock *FalseDest = getBasicBlock(Record[1]); Value *Cond = getValue(Record, 2, NextValueNo, Type::getInt1Ty(Context)); if (!FalseDest || !Cond) return error("Invalid record"); I = BranchInst::Create(TrueDest, FalseDest, Cond); InstructionList.push_back(I); } break; } case bitc::FUNC_CODE_INST_CLEANUPRET: { // CLEANUPRET: [val] or [val,bb#] if (Record.size() != 1 && Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CleanupPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CleanupPad) return error("Invalid record"); BasicBlock *UnwindDest = nullptr; if (Record.size() == 2) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } I = CleanupReturnInst::Create(CleanupPad, UnwindDest); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHRET: { // CATCHRET: [val,bb#] if (Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CatchPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CatchPad) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); I = CatchReturnInst::Create(CatchPad, BB); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHSWITCH: { // CATCHSWITCH: [tok,num,(bb)*,bb?] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumHandlers = Record[Idx++]; SmallVector Handlers; for (unsigned Op = 0; Op != NumHandlers; ++Op) { BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); Handlers.push_back(BB); } BasicBlock *UnwindDest = nullptr; if (Idx + 1 == Record.size()) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } if (Record.size() != Idx) return error("Invalid record"); auto *CatchSwitch = CatchSwitchInst::Create(ParentPad, UnwindDest, NumHandlers); for (BasicBlock *Handler : Handlers) CatchSwitch->addHandler(Handler); I = CatchSwitch; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHPAD: case bitc::FUNC_CODE_INST_CLEANUPPAD: { // [tok,num,(ty,val)*] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumArgOperands = Record[Idx++]; SmallVector Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); Args.push_back(Val); } if (Record.size() != Idx) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_CLEANUPPAD) I = CleanupPadInst::Create(ParentPad, Args); else I = CatchPadInst::Create(ParentPad, Args); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...] // Check magic if ((Record[0] >> 16) == SWITCH_INST_MAGIC) { // "New" SwitchInst format with case ranges. The changes to write this // format were reverted but we still recognize bitcode that uses it. // Hopefully someday we will have support for case ranges and can use // this format again. Type *OpTy = getTypeByID(Record[1]); unsigned ValueBitWidth = cast(OpTy)->getBitWidth(); Value *Cond = getValue(Record, 2, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[3]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = Record[4]; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); unsigned CurIdx = 5; for (unsigned i = 0; i != NumCases; ++i) { SmallVector CaseVals; unsigned NumItems = Record[CurIdx++]; for (unsigned ci = 0; ci != NumItems; ++ci) { bool isSingleNumber = Record[CurIdx++]; APInt Low; unsigned ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; Low = readWideAPInt(makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; if (!isSingleNumber) { ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; APInt High = readWideAPInt( makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; // FIXME: It is not clear whether values in the range should be // compared as signed or unsigned values. The partially // implemented changes that used this format in the past used // unsigned comparisons. for ( ; Low.ule(High); ++Low) CaseVals.push_back(ConstantInt::get(Context, Low)); } else CaseVals.push_back(ConstantInt::get(Context, Low)); } BasicBlock *DestBB = getBasicBlock(Record[CurIdx++]); for (SmallVector::iterator cvi = CaseVals.begin(), cve = CaseVals.end(); cvi != cve; ++cvi) SI->addCase(*cvi, DestBB); } I = SI; break; } // Old SwitchInst format without case ranges. if (Record.size() < 3 || (Record.size() & 1) == 0) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Cond = getValue(Record, 1, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[2]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = (Record.size()-3)/2; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); for (unsigned i = 0, e = NumCases; i != e; ++i) { ConstantInt *CaseVal = dyn_cast_or_null(getFnValueByID(Record[3+i*2], OpTy)); BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]); if (!CaseVal || !DestBB) { delete SI; return error("Invalid record"); } SI->addCase(CaseVal, DestBB); } I = SI; break; } case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...] if (Record.size() < 2) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Address = getValue(Record, 1, NextValueNo, OpTy); if (!OpTy || !Address) return error("Invalid record"); unsigned NumDests = Record.size()-2; IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests); InstructionList.push_back(IBI); for (unsigned i = 0, e = NumDests; i != e; ++i) { if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) { IBI->addDestination(DestBB); } else { delete IBI; return error("Invalid record"); } } I = IBI; break; } case bitc::FUNC_CODE_INST_INVOKE: { // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...] if (Record.size() < 4) return error("Invalid record"); unsigned OpNum = 0; AttributeSet PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; BasicBlock *NormalBB = getBasicBlock(Record[OpNum++]); BasicBlock *UnwindBB = getBasicBlock(Record[OpNum++]); FunctionType *FTy = nullptr; if (CCInfo >> 13 & 1 && !(FTy = dyn_cast(getTypeByID(Record[OpNum++])))) return error("Explicit invoke type is not a function type"); Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) return error("Invalid record"); PointerType *CalleeTy = dyn_cast(Callee->getType()); if (!CalleeTy) return error("Callee is not a pointer"); if (!FTy) { FTy = dyn_cast(CalleeTy->getElementType()); if (!FTy) return error("Callee is not of pointer to function type"); } else if (CalleeTy->getElementType() != FTy) return error("Explicit invoke type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Ops; for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { Ops.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); if (!Ops.back()) return error("Invalid record"); } if (!FTy->isVarArg()) { if (Record.size() != OpNum) return error("Invalid record"); } else { // Read type/value pairs for varargs params. while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Ops.push_back(Op); } } I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops, OperandBundles); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast(CallingConv::MaxID & CCInfo)); cast(I)->setAttributes(PAL); break; } case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval] unsigned Idx = 0; Value *Val = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); I = ResumeInst::Create(Val); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE I = new UnreachableInst(Context); InstructionList.push_back(I); break; case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] if (Record.size() < 1 || ((Record.size()-1)&1)) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2); InstructionList.push_back(PN); for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) { Value *V; // With the new function encoding, it is possible that operands have // negative IDs (for forward references). Use a signed VBR // representation to keep the encoding small. if (UseRelativeIDs) V = getValueSigned(Record, 1+i, NextValueNo, Ty); else V = getValue(Record, 1+i, NextValueNo, Ty); BasicBlock *BB = getBasicBlock(Record[2+i]); if (!V || !BB) return error("Invalid record"); PN->addIncoming(V, BB); } I = PN; break; } case bitc::FUNC_CODE_INST_LANDINGPAD: case bitc::FUNC_CODE_INST_LANDINGPAD_OLD: { // LANDINGPAD: [ty, val, val, num, (id0,val0 ...)?] unsigned Idx = 0; if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD) { if (Record.size() < 3) return error("Invalid record"); } else { IGC_ASSERT(BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD); if (Record.size() < 4) return error("Invalid record"); } Type *Ty = getTypeByID(Record[Idx++]); if (!Ty) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD) { Value *PersFn = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, PersFn)) return error("Invalid record"); if (!F->hasPersonalityFn()) F->setPersonalityFn(cast(PersFn)); else if (F->getPersonalityFn() != cast(PersFn)) return error("Personality function mismatch"); } bool IsCleanup = !!Record[Idx++]; unsigned NumClauses = Record[Idx++]; LandingPadInst *LP = LandingPadInst::Create(Ty, NumClauses); LP->setCleanup(IsCleanup); for (unsigned J = 0; J != NumClauses; ++J) { LandingPadInst::ClauseType CT = LandingPadInst::ClauseType(Record[Idx++]); (void)CT; Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) { delete LP; return error("Invalid record"); } IGC_ASSERT((CT != LandingPadInst::Catch || !isa(Val->getType())) && "Catch clause has a invalid type!"); IGC_ASSERT((CT != LandingPadInst::Filter || isa(Val->getType())) && "Filter clause has invalid type!"); LP->addClause(cast(Val)); } I = LP; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align] if (Record.size() != 4) return error("Invalid record"); uint64_t AlignRecord = Record[3]; const uint64_t InAllocaMask = uint64_t(1) << 5; const uint64_t ExplicitTypeMask = uint64_t(1) << 6; const uint64_t SwiftErrorMask = uint64_t(1) << 7; const uint64_t FlagMask = InAllocaMask | ExplicitTypeMask | SwiftErrorMask; bool InAlloca = AlignRecord & InAllocaMask; bool SwiftError = AlignRecord & SwiftErrorMask; Type *Ty = getTypeByID(Record[0]); if ((AlignRecord & ExplicitTypeMask) == 0) { auto *PTy = dyn_cast_or_null(Ty); if (!PTy) return error("Old-style alloca with a non-pointer type"); Ty = PTy->getElementType(); } Type *OpTy = getTypeByID(Record[1]); Value *Size = getFnValueByID(Record[2], OpTy); unsigned Align; if (Error Err = parseAlignmentValue(AlignRecord & ~FlagMask, Align)) { return Err; } if (!Ty || !Size) return error("Invalid record"); AllocaInst *AI = new AllocaInst(Ty, Size, Align); AI->setUsedWithInAlloca(InAlloca); AI->setSwiftError(SwiftError); I = AI; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || (OpNum + 2 != Record.size() && OpNum + 3 != Record.size())) return error("Invalid record"); Type *Ty = nullptr; if (OpNum + 3 == Record.size()) Ty = getTypeByID(Record[OpNum++]); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; if (!Ty) Ty = cast(Op->getType())->getElementType(); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Ty, Op, "", Record[OpNum + 1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOADATOMIC: { // LOADATOMIC: [opty, op, align, vol, ordering, synchscope] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || (OpNum + 4 != Record.size() && OpNum + 5 != Record.size())) return error("Invalid record"); Type *Ty = nullptr; if (OpNum + 5 == Record.size()) Ty = getTypeByID(Record[OpNum++]); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; if (!Ty) Ty = cast(Op->getType())->getElementType(); AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Release || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); SynchronizationScope SynchScope = getDecodedSynchScope(Record[OpNum + 3]); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Op, "", Record[OpNum+1], Align, Ordering, SynchScope); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STORE: case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol] unsigned OpNum = 0; Value *Val, *Ptr; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || (BitCode == bitc::FUNC_CODE_INST_STORE ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val)) || OpNum + 2 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum+1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STOREATOMIC: case bitc::FUNC_CODE_INST_STOREATOMIC_OLD: { // STOREATOMIC: [ptrty, ptr, val, align, vol, ordering, synchscope] unsigned OpNum = 0; Value *Val, *Ptr; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || !isa(Ptr->getType()) || (BitCode == bitc::FUNC_CODE_INST_STOREATOMIC ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val)) || OpNum + 4 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Acquire || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); SynchronizationScope SynchScope = getDecodedSynchScope(Record[OpNum + 3]); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum+1], Align, Ordering, SynchScope); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMPXCHG_OLD: case bitc::FUNC_CODE_INST_CMPXCHG: { // CMPXCHG:[ptrty, ptr, cmp, new, vol, successordering, synchscope, // failureordering?, isweak?] unsigned OpNum = 0; Value *Ptr, *Cmp, *New; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || (BitCode == bitc::FUNC_CODE_INST_CMPXCHG ? getValueTypePair(Record, OpNum, NextValueNo, Cmp) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Cmp)) || popValue(Record, OpNum, NextValueNo, Cmp->getType(), New) || Record.size() < OpNum + 3 || Record.size() > OpNum + 5) return error("Invalid record"); AtomicOrdering SuccessOrdering = getDecodedOrdering(Record[OpNum + 1]); if (SuccessOrdering == AtomicOrdering::NotAtomic || SuccessOrdering == AtomicOrdering::Unordered) return error("Invalid record"); SynchronizationScope SynchScope = getDecodedSynchScope(Record[OpNum + 2]); if (Error Err = typeCheckLoadStoreInst(Cmp->getType(), Ptr->getType())) return Err; AtomicOrdering FailureOrdering; if (Record.size() < 7) FailureOrdering = AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrdering); else FailureOrdering = getDecodedOrdering(Record[OpNum + 3]); I = new AtomicCmpXchgInst(Ptr, Cmp, New, SuccessOrdering, FailureOrdering, SynchScope); cast(I)->setVolatile(Record[OpNum]); if (Record.size() < 8) { // Before weak cmpxchgs existed, the instruction simply returned the // value loaded from memory, so bitcode files from that era will be // expecting the first component of a modern cmpxchg. CurBB->getInstList().push_back(I); I = ExtractValueInst::Create(I, 0); } else { cast(I)->setWeak(Record[OpNum+4]); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ATOMICRMW: { // ATOMICRMW:[ptrty, ptr, val, op, vol, ordering, synchscope] unsigned OpNum = 0; Value *Ptr, *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || !isa(Ptr->getType()) || popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val) || OpNum+4 != Record.size()) return error("Invalid record"); AtomicRMWInst::BinOp Operation = getDecodedRMWOperation(Record[OpNum]); if (Operation < AtomicRMWInst::FIRST_BINOP || Operation > AtomicRMWInst::LAST_BINOP) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered) return error("Invalid record"); SynchronizationScope SynchScope = getDecodedSynchScope(Record[OpNum + 3]); I = new AtomicRMWInst(Operation, Ptr, Val, Ordering, SynchScope); cast(I)->setVolatile(Record[OpNum+1]); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_FENCE: { // FENCE:[ordering, synchscope] if (2 != Record.size()) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[0]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered || Ordering == AtomicOrdering::Monotonic) return error("Invalid record"); SynchronizationScope SynchScope = getDecodedSynchScope(Record[1]); I = new FenceInst(Context, Ordering, SynchScope); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CALL: { // CALL: [paramattrs, cc, fmf, fnty, fnid, arg0, arg1...] if (Record.size() < 3) return error("Invalid record"); unsigned OpNum = 0; AttributeSet PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; FastMathFlags FMF; if ((CCInfo >> bitc::CALL_FMF) & 1) { FMF = getDecodedFastMathFlags(Record[OpNum++]); if (!FMF.any()) return error("Fast math flags indicator set for call with no FMF"); } FunctionType *FTy = nullptr; if (CCInfo >> bitc::CALL_EXPLICIT_TYPE & 1 && !(FTy = dyn_cast(getTypeByID(Record[OpNum++])))) return error("Explicit call type is not a function type"); Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) return error("Invalid record"); PointerType *OpTy = dyn_cast(Callee->getType()); if (!OpTy) return error("Callee is not a pointer type"); if (!FTy) { FTy = dyn_cast(OpTy->getElementType()); if (!FTy) return error("Callee is not of pointer to function type"); } else if (OpTy->getElementType() != FTy) return error("Explicit call type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Args; // Read the fixed params. for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { if (FTy->getParamType(i)->isLabelTy()) Args.push_back(getBasicBlock(Record[OpNum])); else Args.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); if (!Args.back()) return error("Invalid record"); } // Read type/value pairs for varargs params. if (!FTy->isVarArg()) { if (OpNum != Record.size()) return error("Invalid record"); } else { while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Args.push_back(Op); } } I = CallInst::Create(FTy, Callee, Args, OperandBundles); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast((0x7ff & CCInfo) >> bitc::CALL_CCONV)); CallInst::TailCallKind TCK = CallInst::TCK_None; if (CCInfo & 1 << bitc::CALL_TAIL) TCK = CallInst::TCK_Tail; if (CCInfo & (1 << bitc::CALL_MUSTTAIL)) TCK = CallInst::TCK_MustTail; if (CCInfo & (1 << bitc::CALL_NOTAIL)) TCK = CallInst::TCK_NoTail; cast(I)->setTailCallKind(TCK); cast(I)->setAttributes(PAL); if (FMF.any()) { if (!isa(I)) return error("Fast-math-flags specified for call without " "floating-point scalar or vector return type"); I->setFastMathFlags(FMF); } break; } case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty] if (Record.size() < 3) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Op = getValue(Record, 1, NextValueNo, OpTy); Type *ResTy = getTypeByID(Record[2]); if (!OpTy || !Op || !ResTy) return error("Invalid record"); I = new VAArgInst(Op, ResTy); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_OPERAND_BUNDLE: { // A call or an invoke can be optionally prefixed with some variable // number of operand bundle blocks. These blocks are read into // OperandBundles and consumed at the next call or invoke instruction. if (Record.size() < 1 || Record[0] >= BundleTags.size()) return error("Invalid record"); std::vector Inputs; unsigned OpNum = 1; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Inputs.push_back(Op); } OperandBundles.emplace_back(BundleTags[Record[0]], std::move(Inputs)); continue; } } // Add instruction to end of current BB. If there is no current BB, reject // this file. if (!CurBB) { delete I; return error("Invalid instruction with no BB"); } if (!OperandBundles.empty()) { delete I; return error("Operand bundles found with no consumer"); } CurBB->getInstList().push_back(I); // If this was a terminator instruction, move to the next block. if (isa(I)) { ++CurBBNo; CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr; } // Non-void values get registered in the value table for future use. if (I && !I->getType()->isVoidTy()) ValueList.assignValue(I, NextValueNo++); } OutOfRecordLoop: if (!OperandBundles.empty()) return error("Operand bundles found with no consumer"); // Check the function list for unresolved values. if (Argument *A = dyn_cast(ValueList.back())) { if (!A->getParent()) { // We found at least one unresolved value. Nuke them all to avoid leaks. for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){ if ((A = dyn_cast_or_null(ValueList[i])) && !A->getParent()) { A->replaceAllUsesWith(UndefValue::get(A->getType())); delete A; } } return error("Never resolved value found in function"); } } // Unexpected unresolved metadata about to be dropped. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: outgoing forward refs"); // Trim the value list down to the size it was before we parsed this function. ValueList.shrinkTo(ModuleValueListSize); MDLoader->shrinkTo(ModuleMDLoaderSize); std::vector().swap(FunctionBBs); return Error::success(); } /// Find the function body in the bitcode stream Error BitcodeReader::findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator) { while (DeferredFunctionInfoIterator->second == 0) { // This is the fallback handling for the old format bitcode that // didn't contain the function index in the VST, or when we have // an anonymous function which would not have a VST entry. // Assert that we have one of those two cases. IGC_ASSERT(VSTOffset == 0 || !F->hasName()); // Parse the next body in the stream and set its position in the // DeferredFunctionInfo map. if (Error Err = rememberAndSkipFunctionBodies()) return Err; } return Error::success(); } //===----------------------------------------------------------------------===// // GVMaterializer implementation //===----------------------------------------------------------------------===// Error BitcodeReader::materialize(GlobalValue *GV) { Function *F = dyn_cast(GV); // If it's not a function or is already material, ignore the request. if (!F || !F->isMaterializable()) return Error::success(); DenseMap::iterator DFII = DeferredFunctionInfo.find(F); IGC_ASSERT(DFII != DeferredFunctionInfo.end() && "Deferred function not found!"); // If its position is recorded as 0, its body is somewhere in the stream // but we haven't seen it yet. if (DFII->second == 0) if (Error Err = findFunctionInStream(F, DFII)) return Err; // Materialize metadata before parsing any function bodies. if (Error Err = materializeMetadata()) return Err; // Move the bit stream to the saved position of the deferred function body. Stream.JumpToBit(DFII->second); if (Error Err = parseFunctionBody(F)) return Err; F->setIsMaterializable(false); if (StripDebugInfo) stripDebugInfo(*F); // Upgrade any old intrinsic calls in the function. for (auto &I : UpgradedIntrinsics) { for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) { User *U = *UI; ++UI; if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } } // Update calls to the remangled intrinsics for (auto &I : RemangledIntrinsics) for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) // Don't expect any other users than call sites CallSite(*UI++).setCalledFunction(I.second); // Finish fn->subprogram upgrade for materialized functions. if (DISubprogram *SP = MDLoader->lookupSubprogramForFunction(F)) F->setSubprogram(SP); // Check if the TBAA Metadata are valid, otherwise we will need to strip them. if (!MDLoader->isStrippingTBAA()) { for (auto &I : instructions(F)) { MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa); if (!TBAA || TBAAVerifyHelper.visitTBAAMetadata(I, TBAA)) continue; MDLoader->setStripTBAA(true); stripTBAA(F->getParent()); } } // Bring in any functions that this function forward-referenced via // blockaddresses. return materializeForwardReferencedFunctions(); } Error BitcodeReader::materializeModule() { if (Error Err = materializeMetadata()) return Err; // Promise to materialize all forward references. WillMaterializeAllForwardRefs = true; // Iterate over the module, deserializing any functions that are still on // disk. for (Function &F : *TheModule) { if (Error Err = materialize(&F)) return Err; } // At this point, if there are any function bodies, parse the rest of // the bits in the module past the last function block we have recorded // through either lazy scanning or the VST. if (LastFunctionBlockBit || NextUnreadBit) if (Error Err = parseModule(LastFunctionBlockBit > NextUnreadBit ? LastFunctionBlockBit : NextUnreadBit)) return Err; // Check that all block address forward references got resolved (as we // promised above). if (!BasicBlockFwdRefs.empty()) return error("Never resolved function from blockaddress"); // Upgrade any intrinsic calls that slipped through (should not happen!) and // delete the old functions to clean up. We can't do this unless the entire // module is materialized because there could always be another function body // with calls to the old function. for (auto &I : UpgradedIntrinsics) { for (auto *U : I.first->users()) { if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } if (!I.first->use_empty()) I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } UpgradedIntrinsics.clear(); // Do the same for remangled intrinsics for (auto &I : RemangledIntrinsics) { I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } RemangledIntrinsics.clear(); UpgradeDebugInfo(*TheModule); UpgradeModuleFlags(*TheModule); return Error::success(); } std::vector BitcodeReader::getIdentifiedStructTypes() const { return IdentifiedStructTypes; } ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader( BitstreamCursor Cursor, ModuleSummaryIndex &TheIndex) : BitcodeReaderBase(std::move(Cursor)), TheIndex(TheIndex) {} std::pair ModuleSummaryIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) { auto VGI = ValueIdToCallGraphGUIDMap.find(ValueId); IGC_ASSERT(VGI != ValueIdToCallGraphGUIDMap.end()); return VGI->second; } // Specialized value symbol table parser used when reading module index // blocks where we don't actually create global values. The parsed information // is saved in the bitcode reader for use when later parsing summaries. Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap) { IGC_ASSERT(Offset > 0 && "Expected non-zero VST offset"); uint64_t CurrentBit = jumpToValueSymbolTable(Offset, Stream); if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this value table. SmallString<128> ValueName; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // Done parsing VST, jump back to wherever we came from. Stream.JumpToBit(CurrentBit); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore (e.g. VST_CODE_BBENTRY records). break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] if (convertToString(Record, 1, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; std::string GlobalId = GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName); auto ValueGUID = GlobalValue::getGUID(GlobalId); auto OriginalNameID = ValueGUID; if (GlobalValue::isLocalLinkage(Linkage)) OriginalNameID = GlobalValue::getGUID(ValueName); ValueIdToCallGraphGUIDMap[ValueID] = std::make_pair(ValueGUID, OriginalNameID); ValueName.clear(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] if (convertToString(Record, 2, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; std::string FunctionGlobalId = GlobalValue::getGlobalIdentifier( ValueName, VLI->second, SourceFileName); auto FunctionGUID = GlobalValue::getGUID(FunctionGlobalId); auto OriginalNameID = FunctionGUID; if (GlobalValue::isLocalLinkage(Linkage)) OriginalNameID = GlobalValue::getGUID(ValueName); ValueIdToCallGraphGUIDMap[ValueID] = std::make_pair(FunctionGUID, OriginalNameID); ValueName.clear(); break; } case bitc::VST_CODE_COMBINED_ENTRY: { // VST_CODE_COMBINED_ENTRY: [valueid, refguid] unsigned ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; // The "original name", which is the second value of the pair will be // overriden later by a FS_COMBINED_ORIGINAL_NAME in the combined index. ValueIdToCallGraphGUIDMap[ValueID] = std::make_pair(RefGUID, RefGUID); break; } } } } // Parse just the blocks needed for building the index out of the module. // At the end of this routine the module Index is populated with a map // from global value id to GlobalValueSummary objects. Error ModuleSummaryIndexBitcodeReader::parseModule(StringRef ModulePath) { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; DenseMap ValueIdToLinkageMap; unsigned ValueId = 0; // Read the index for this module. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::BLOCKINFO_BLOCK_ID: // Need to parse these to get abbrev ids (e.g. for VST) if (readBlockInfo()) return error("Malformed block"); break; case bitc::VALUE_SYMTAB_BLOCK_ID: // Should have been parsed earlier via VSTOffset, unless there // is no summary section. IGC_ASSERT(((SeenValueSymbolTable && VSTOffset > 0) || !SeenGlobalValSummary) && "Expected early VST parse via VSTOffset record"); if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: IGC_ASSERT(!SeenValueSymbolTable && "Already read VST when parsing summary block?"); // We might not have a VST if there were no values in the // summary. An empty summary block generated when we are // performing ThinLTO compiles so we don't later invoke // the regular LTO process on them. if (VSTOffset > 0) { if (Error Err = parseValueSymbolTable(VSTOffset, ValueIdToLinkageMap)) return Err; SeenValueSymbolTable = true; } SeenGlobalValSummary = true; if (Error Err = parseEntireSummary(ModulePath)) return Err; break; case bitc::MODULE_STRTAB_BLOCK_ID: if (Error Err = parseModuleStringTable()) return Err; break; } continue; case BitstreamEntry::Record: { Record.clear(); auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: break; // Default behavior, ignore unknown content. /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: { SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); SourceFileName = ValueName.c_str(); break; } /// MODULE_CODE_HASH: [5*i32] case bitc::MODULE_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); if (TheIndex.modulePaths().empty()) // We always seed the index with the module. TheIndex.addModulePath(ModulePath, 0); if (TheIndex.modulePaths().size() != 1) return error("Don't expect multiple modules defined?"); auto &Hash = TheIndex.modulePaths().begin()->second.second; int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); Hash[Pos++] = Val; } break; } /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one // word before the start of the identification or module block, which // was historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; // GLOBALVAR: [pointer type, isconst, initid, // linkage, alignment, section, visibility, threadlocal, // unnamed_addr, externally_initialized, dllstorageclass, // comdat] case bitc::MODULE_CODE_GLOBALVAR: { if (Record.size() < 6) return error("Invalid record"); uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); ValueIdToLinkageMap[ValueId++] = Linkage; break; } // FUNCTION: [type, callingconv, isproto, linkage, paramattr, // alignment, section, visibility, gc, unnamed_addr, // prologuedata, dllstorageclass, comdat, prefixdata] case bitc::MODULE_CODE_FUNCTION: { if (Record.size() < 8) return error("Invalid record"); uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); ValueIdToLinkageMap[ValueId++] = Linkage; break; } // ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, // dllstorageclass] case bitc::MODULE_CODE_ALIAS: { if (Record.size() < 6) return error("Invalid record"); uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); ValueIdToLinkageMap[ValueId++] = Linkage; break; } } } continue; } } } std::vector ModuleSummaryIndexBitcodeReader::makeRefList(ArrayRef Record) { std::vector Ret; Ret.reserve(Record.size()); for (uint64_t RefValueId : Record) Ret.push_back(getGUIDFromValueId(RefValueId).first); return Ret; } std::vector ModuleSummaryIndexBitcodeReader::makeCallList( ArrayRef Record, bool IsOldProfileFormat, bool HasProfile) { std::vector Ret; Ret.reserve(Record.size()); for (unsigned I = 0, E = Record.size(); I != E; ++I) { CalleeInfo::HotnessType Hotness = CalleeInfo::HotnessType::Unknown; GlobalValue::GUID CalleeGUID = getGUIDFromValueId(Record[I]).first; if (IsOldProfileFormat) { I += 1; // Skip old callsitecount field if (HasProfile) I += 1; // Skip old profilecount field } else if (HasProfile) Hotness = static_cast(Record[++I]); Ret.push_back(FunctionSummary::EdgeTy{CalleeGUID, CalleeInfo{Hotness}}); } return Ret; } // Eagerly parse the entire summary block. This populates the GlobalValueSummary // objects in the index. Error ModuleSummaryIndexBitcodeReader::parseEntireSummary( StringRef ModulePath) { if (Stream.EnterSubBlock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Parse version { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); if (Entry.Kind != BitstreamEntry::Record) return error("Invalid Summary Block: record for version expected"); if (Stream.readRecord(Entry.ID, Record) != bitc::FS_VERSION) return error("Invalid Summary Block: version expected"); } const uint64_t Version = Record[0]; const bool IsOldProfileFormat = Version == 1; if (Version < 1 || Version > 3) return error("Invalid summary version " + Twine(Version) + ", 1, 2 or 3 expected"); Record.clear(); // Keep around the last seen summary to be used when we see an optional // "OriginalName" attachement. GlobalValueSummary *LastSeenSummary = nullptr; bool Combined = false; std::vector PendingTypeTests; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // For a per-module index, remove any entries that still have empty // summaries. The VST parsing creates entries eagerly for all symbols, // but not all have associated summaries (e.g. it doesn't know how to // distinguish between VST_CODE_ENTRY for function declarations vs global // variables with initializers that end up with a summary). Remove those // entries now so that we don't need to rely on the combined index merger // to clean them up (especially since that may not run for the first // module's index if we merge into that). if (!Combined) TheIndex.removeEmptySummaryEntries(); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. The record format depends on whether this // is a per-module index or a combined index file. In the per-module // case the records contain the associated value's ID for correlation // with VST entries. In the combined index the correlation is done // via the bitcode offset of the summary records (which were saved // in the combined index VST entries). The records also contain // information used for ThinLTO renaming and importing. Record.clear(); auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: ignore. break; // FS_PERMODULE: [valueid, flags, instcount, numrefs, numrefs x valueid, // n x (valueid)] // FS_PERMODULE_PROFILE: [valueid, flags, instcount, numrefs, // numrefs x valueid, // n x (valueid, hotness)] case bitc::FS_PERMODULE: case bitc::FS_PERMODULE_PROFILE: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned InstCount = Record[2]; unsigned NumRefs = Record[3]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. static int RefListStartIndex = 4; int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_PERMODULE_PROFILE); std::vector Calls = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile); auto FS = llvm::make_unique( Flags, InstCount, std::move(Refs), std::move(Calls), std::move(PendingTypeTests)); PendingTypeTests.clear(); auto GUID = getGUIDFromValueId(ValueID); FS->setModulePath(TheIndex.addModulePath(ModulePath, 0)->first()); FS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(FS)); break; } // FS_ALIAS: [valueid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_PERMODULE entries, as // they expect all aliasee summaries to be available. case bitc::FS_ALIAS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned AliaseeID = Record[2]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = llvm::make_unique(Flags, std::vector{}); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. AS->setModulePath(TheIndex.addModulePath(ModulePath, 0)->first()); GlobalValue::GUID AliaseeGUID = getGUIDFromValueId(AliaseeID).first; auto *AliaseeSummary = TheIndex.getGlobalValueSummary(AliaseeGUID); if (!AliaseeSummary) return error("Alias expects aliasee summary to be parsed"); AS->setAliasee(AliaseeSummary); auto GUID = getGUIDFromValueId(ValueID); AS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(AS)); break; } // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, n x valueid] case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); std::vector Refs = makeRefList(ArrayRef(Record).slice(2)); auto FS = llvm::make_unique(Flags, std::move(Refs)); FS->setModulePath(TheIndex.addModulePath(ModulePath, 0)->first()); auto GUID = getGUIDFromValueId(ValueID); FS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(FS)); break; } // FS_COMBINED: [valueid, modid, flags, instcount, numrefs, // numrefs x valueid, n x (valueid)] // FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, numrefs, // numrefs x valueid, n x (valueid, hotness)] case bitc::FS_COMBINED: case bitc::FS_COMBINED_PROFILE: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned InstCount = Record[3]; unsigned NumRefs = Record[4]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); static int RefListStartIndex = 5; int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_COMBINED_PROFILE); std::vector Edges = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile); GlobalValue::GUID GUID = getGUIDFromValueId(ValueID).first; auto FS = llvm::make_unique( Flags, InstCount, std::move(Refs), std::move(Edges), std::move(PendingTypeTests)); PendingTypeTests.clear(); LastSeenSummary = FS.get(); FS->setModulePath(ModuleIdMap[ModuleId]); TheIndex.addGlobalValueSummary(GUID, std::move(FS)); Combined = true; break; } // FS_COMBINED_ALIAS: [valueid, modid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_COMBINED entries, as // they expect all aliasee summaries to be available. case bitc::FS_COMBINED_ALIAS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned AliaseeValueId = Record[3]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = llvm::make_unique(Flags, std::vector{}); LastSeenSummary = AS.get(); AS->setModulePath(ModuleIdMap[ModuleId]); auto AliaseeGUID = getGUIDFromValueId(AliaseeValueId).first; auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeGUID, AS->modulePath()); if (!AliaseeInModule) return error("Alias expects aliasee summary to be parsed"); AS->setAliasee(AliaseeInModule); GlobalValue::GUID GUID = getGUIDFromValueId(ValueID).first; TheIndex.addGlobalValueSummary(GUID, std::move(AS)); Combined = true; break; } // FS_COMBINED_GLOBALVAR_INIT_REFS: [valueid, modid, flags, n x valueid] case bitc::FS_COMBINED_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); std::vector Refs = makeRefList(ArrayRef(Record).slice(3)); auto FS = llvm::make_unique(Flags, std::move(Refs)); LastSeenSummary = FS.get(); FS->setModulePath(ModuleIdMap[ModuleId]); GlobalValue::GUID GUID = getGUIDFromValueId(ValueID).first; TheIndex.addGlobalValueSummary(GUID, std::move(FS)); Combined = true; break; } // FS_COMBINED_ORIGINAL_NAME: [original_name] case bitc::FS_COMBINED_ORIGINAL_NAME: { uint64_t OriginalName = Record[0]; if (!LastSeenSummary) return error("Name attachment that does not follow a combined record"); LastSeenSummary->setOriginalName(OriginalName); // Reset the LastSeenSummary LastSeenSummary = nullptr; break; } case bitc::FS_TYPE_TESTS: { IGC_ASSERT(PendingTypeTests.empty()); PendingTypeTests.insert(PendingTypeTests.end(), Record.begin(), Record.end()); break; } } } llvm_unreachable("Exit infinite loop"); } // Parse the module string table block into the Index. // This populates the ModulePathStringTable map in the index. Error ModuleSummaryIndexBitcodeReader::parseModuleStringTable() { if (Stream.EnterSubBlock(bitc::MODULE_STRTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; SmallString<128> ModulePath; ModulePathStringTableTy::iterator LastSeenModulePath; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::MST_CODE_ENTRY: { // MST_ENTRY: [modid, namechar x N] uint64_t ModuleId = Record[0]; if (convertToString(Record, 1, ModulePath)) return error("Invalid record"); LastSeenModulePath = TheIndex.addModulePath(ModulePath, ModuleId); ModuleIdMap[ModuleId] = LastSeenModulePath->first(); ModulePath.clear(); break; } /// MST_CODE_HASH: [5*i32] case bitc::MST_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); if (LastSeenModulePath == TheIndex.modulePaths().end()) return error("Invalid hash that does not follow a module path"); int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); LastSeenModulePath->second.second[Pos++] = Val; } // Reset LastSeenModulePath to avoid overriding the hash unexpectedly. LastSeenModulePath = TheIndex.modulePaths().end(); break; } } } llvm_unreachable("Exit infinite loop"); } namespace upgrader { // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. class BitcodeErrorCategoryType : public std::error_category { const char *name() const noexcept override { return "llvm.bitcode"; } std::string message(int IE) const override { BitcodeError E = static_cast(IE); switch (E) { case BitcodeError::CorruptedBitcode: return "Corrupted bitcode"; } llvm_unreachable("Unknown error type!"); } }; static ManagedStatic ErrorCategory; const std::error_category &BitcodeErrorCategory() { return *ErrorCategory; } } // end namespace upgrader //===----------------------------------------------------------------------===// // External interface //===----------------------------------------------------------------------===// namespace upgrader { Expected> getBitcodeModuleList(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); BitstreamCursor &Stream = *StreamOrErr; std::vector Modules; while (true) { uint64_t BCBegin = Stream.getCurrentByteNo(); // We may be consuming bitcode from a client that leaves garbage at the end // of the bitcode stream. If we are close enough to // the end that there cannot possibly be another module, stop looking. if (BCBegin + 8 >= Stream.getBitcodeBytes().size()) return Modules; BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: { uint64_t IdentificationBit = -1ull; if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) { IdentificationBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Stream.SkipBlock()) return error("Malformed block"); Entry = Stream.advance(); if (Entry.Kind != BitstreamEntry::SubBlock || Entry.ID != bitc::MODULE_BLOCK_ID) return error("Malformed block"); } if (Entry.ID == bitc::MODULE_BLOCK_ID) { uint64_t ModuleBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Stream.SkipBlock()) return error("Malformed block"); Modules.push_back({ Stream.getBitcodeBytes().slice( BCBegin, Stream.getCurrentByteNo() - BCBegin), Buffer.getBufferIdentifier(), IdentificationBit, ModuleBit }); continue; } if (Stream.SkipBlock()) return error("Malformed block"); continue; } case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } /// \brief Get a lazy one-at-time loading module from bitcode. /// /// This isn't always used in a lazy context. In particular, it's also used by /// \a parseModule(). If this is truly lazy, then we need to eagerly pull /// in forward-referenced functions from block address references. /// /// \param[in] MaterializeAll Set to \c true if we should materialize /// everything. Expected> BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting) { BitstreamCursor Stream(Buffer); std::string ProducerIdentification; if (IdentificationBit != -1ull) { Stream.JumpToBit(IdentificationBit); Expected ProducerIdentificationOrErr = readIdentificationBlock(Stream); if (!ProducerIdentificationOrErr) return ProducerIdentificationOrErr.takeError(); ProducerIdentification = *ProducerIdentificationOrErr; } Stream.JumpToBit(ModuleBit); auto *R = new BitcodeReader(std::move(Stream), ProducerIdentification, Context); std::unique_ptr M = llvm::make_unique(ModuleIdentifier, Context); M->setMaterializer(R); // Delay parsing Metadata if ShouldLazyLoadMetadata is true. if (Error Err = R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata, IsImporting)) return std::move(Err); if (MaterializeAll) { // Read in the entire module, and destroy the BitcodeReader. if (Error Err = M->materializeAll()) return std::move(Err); } else { // Resolve forward references from blockaddresses. if (Error Err = R->materializeForwardReferencedFunctions()) return std::move(Err); } return std::move(M); } Expected> BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { return getModuleImpl(Context, false, ShouldLazyLoadMetadata, IsImporting); } // Parse the specified bitcode buffer, returning the function info index. Expected> BitcodeModule::getSummary() { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); auto Index = llvm::make_unique(); ModuleSummaryIndexBitcodeReader R(std::move(Stream), *Index); if (Error Err = R.parseModule(ModuleIdentifier)) return std::move(Err); return std::move(Index); } // Check if the given bitcode buffer contains a global value summary block. Expected BitcodeModule::hasSummary() { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) return true; // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } } //end of namespace upgrader namespace upgrader { static Expected getSingleModule(MemoryBufferRef Buffer) { Expected> MsOrErr = upgrader::getBitcodeModuleList(Buffer); if (!MsOrErr) return MsOrErr.takeError(); if (MsOrErr->size() != 1) return error("Expected a single module"); return (*MsOrErr)[0]; } Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLazyModule(Context, ShouldLazyLoadMetadata, IsImporting); } } static Expected> getOwningLazyBitcodeModule( std::unique_ptr &&Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { auto MOrErr = getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata, IsImporting); if (MOrErr) (*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer)); return MOrErr; } namespace upgrader { Expected> BitcodeModule::parseModule(LLVMContext &Context) { return getModuleImpl(Context, true, false, false); // TODO: Restore the use-lists to the in-memory state when the bitcode was // written. We must defer until the Module has been fully materialized. } Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->parseModule(Context); } Expected getBitcodeTargetTriple(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readTriple(*StreamOrErr); } Expected isBitcodeContainingObjCCategory(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return hasObjCCategory(*StreamOrErr); } Expected getBitcodeProducerString(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readIdentificationCode(*StreamOrErr); } Expected> getModuleSummaryIndex(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getSummary(); } Expected hasGlobalValueSummary(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->hasSummary(); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm4/BitcodeReader.h000066400000000000000000000151761363533017100272550ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- BitcodeReader.h - Internal BitcodeReader impl ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This header defines the BitcodeReader class. // //===----------------------------------------------------------------------===// #ifndef __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #define __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #include "common/LLVMWarningsPush.hpp" #include #include #include #include "llvm/Bitcode/BitcodeReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common/LLVMWarningsPop.hpp" namespace upgrader { using namespace llvm; /// Represents a module in a bitcode file. class BitcodeModule { // This covers the identification (if present) and module blocks. ArrayRef Buffer; StringRef ModuleIdentifier; // The bitstream location of the IDENTIFICATION_BLOCK. uint64_t IdentificationBit; // The bitstream location of this module's MODULE_BLOCK. uint64_t ModuleBit; BitcodeModule(ArrayRef Buffer, StringRef ModuleIdentifier, uint64_t IdentificationBit, uint64_t ModuleBit) : Buffer(Buffer), ModuleIdentifier(ModuleIdentifier), IdentificationBit(IdentificationBit), ModuleBit(ModuleBit) {} // Calls the ctor. friend Expected> getBitcodeModuleList(MemoryBufferRef Buffer); Expected> getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting); public: StringRef getBuffer() const { return StringRef((const char *)Buffer.begin(), Buffer.size()); } StringRef getModuleIdentifier() const { return ModuleIdentifier; } /// Read the bitcode module and prepare for lazy deserialization of function /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well. /// If IsImporting is true, this module is being parsed for ThinLTO /// importing into another module. Expected> getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting); /// Read the entire bitcode module and return it. Expected> parseModule(LLVMContext &Context); /// Check if the given bitcode buffer contains a summary block. Expected hasSummary(); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getSummary(); }; /// Returns a list of modules in the specified bitcode buffer. //Expected> //getBitcodeModuleList(MemoryBufferRef Buffer); /// Read the header of the specified bitcode buffer and prepare for lazy /// deserialization of function bodies. If ShouldLazyLoadMetadata is true, /// lazily load metadata as well. If IsImporting is true, this module is /// being parsed for ThinLTO importing into another module. Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); #if 0 /// Read the header of the specified bitcode buffer and prepare for lazy /// deserialization of function bodies. If successful, this moves Buffer. On /// error, this *does not* move Buffer. ErrorOr getLazyBitcodeModule(std::unique_ptr &&Buffer, LLVMContext &Context, DiagnosticHandlerFunction DiagnosticHandler = nullptr); /// Read the header of the specified stream and prepare for lazy /// deserialization and streaming of function bodies. ErrorOr> getStreamedBitcodeModule( StringRef Name, DataStreamer *Streamer, LLVMContext &Context, DiagnosticHandlerFunction DiagnosticHandler = nullptr); /// Read the header of the specified bitcode buffer and extract just the /// triple information. If successful, this returns a string. On error, this /// returns "". std::string getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context, DiagnosticHandlerFunction DiagnosticHandler = nullptr); /// Read the specified bitcode file, returning the module. ErrorOr parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context, DiagnosticHandlerFunction DiagnosticHandler = nullptr); #endif } // End upgrader namespace #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm4/MetadataLoader.h000066400000000000000000000073331363533017100274240ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===-- Bitcode/Reader/MetadataLoader.h - Load Metadatas -------*- C++ -*-====// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class handles loading Metadatas. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_METADATALOADER_H #define LLVM_LIB_BITCODE_READER_METADATALOADER_H #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Error.h" #include #include namespace llvm { class BitcodeReaderValueList; class BitstreamCursor; class DISubprogram; class Error; class Function; class Instruction; class Metadata; class MDNode; class Module; class Type; /// Helper class that handles loading Metadatas and keeping them available. class MetadataLoader { class MetadataLoaderImpl; std::unique_ptr Pimpl; Error parseMetadata(bool ModuleLevel); public: ~MetadataLoader(); MetadataLoader(BitstreamCursor &Stream, Module &TheModule, BitcodeReaderValueList &ValueList, bool IsImporting, std::function getTypeByID); MetadataLoader &operator=(MetadataLoader &&); MetadataLoader(MetadataLoader &&); // Parse a module metadata block Error parseModuleMetadata() { return parseMetadata(true); } // Parse a function metadata block Error parseFunctionMetadata() { return parseMetadata(false); } /// Set the mode to strip TBAA metadata on load. void setStripTBAA(bool StripTBAA = true); /// Return true if the Loader is stripping TBAA metadata. bool isStrippingTBAA(); // Return true there are remaining unresolved forward references. bool hasFwdRefs() const; /// Return the given metadata, creating a replaceable forward reference if /// necessary. Metadata *getMetadataFwdRefOrLoad(unsigned Idx); MDNode *getMDNodeFwdRefOrNull(unsigned Idx); /// Return the DISubprogra metadata for a Function if any, null otherwise. DISubprogram *lookupSubprogramForFunction(Function *F); /// Parse a `METADATA_ATTACHMENT` block for a function. Error parseMetadataAttachment( Function &F, const SmallVectorImpl &InstructionList); /// Parse a `METADATA_KIND` block for the current module. Error parseMetadataKinds(); unsigned size() const; void shrinkTo(unsigned N); }; } #endif // LLVM_LIB_BITCODE_READER_METADATALOADER_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm4/Upgrader.cpp000066400000000000000000000043431363533017100266570ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "Upgrader.h" #include "common/LLVMWarningsPush.hpp" #include "llvmWrapper/Bitcode/BitcodeWriter.h" #include "llvm/Bitcode/BitcodeReader.h" #include #include #include "common/LLVMWarningsPop.hpp" using namespace llvm; std::unique_ptr upgrader::upgradeBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { auto ErrM = upgrader::parseBitcodeFile(Buffer, Context); Module *M = ErrM.get().get(); if (!M) return nullptr; SmallVector Buf; Buf.reserve(1024*1024); raw_svector_ostream OS(Buf); IGCLLVM::WriteBitcodeToFile(M, OS); return MemoryBuffer::getMemBufferCopy(OS.str()); } Expected> upgrader::upgradeAndParseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { return upgrader::parseBitcodeFile(Buffer, Context); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm4/Upgrader.h000066400000000000000000000036741363533017100263320ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #ifndef __DRIVERINTERFACE_UPGRADER_H__ #define __DRIVERINTERFACE_UPGRADER_H__ #include "common/LLVMWarningsPush.hpp" #include #include #include #include #include "common/LLVMWarningsPop.hpp" namespace upgrader { llvm::Expected> parseBitcodeFile(llvm::MemoryBufferRef Buffer, llvm::LLVMContext &Context); std::unique_ptr upgradeBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); llvm::Expected> upgradeAndParseBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); } // End upgrader namespace #endif // __DRIVERINTERFACE_UPGRADER_H__ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm4/ValueList.h000066400000000000000000000070441363533017100264640ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===-- Bitcode/Reader/ValueEnumerator.h - Number values --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class gives values and types Unique ID's. // //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" #include "llvm/IR/ValueHandle.h" #include #include "Probe.h" namespace llvm { class Constant; class BitcodeReaderValueList { std::vector ValuePtrs; /// As we resolve forward-referenced constants, we add information about them /// to this vector. This allows us to resolve them in bulk instead of /// resolving each reference at a time. See the code in /// ResolveConstantForwardRefs for more information about this. /// /// The key of this vector is the placeholder constant, the value is the slot /// number that holds the resolved value. typedef std::vector> ResolveConstantsTy; ResolveConstantsTy ResolveConstants; LLVMContext &Context; public: BitcodeReaderValueList(LLVMContext &C) : Context(C) {} ~BitcodeReaderValueList() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); } // vector compatibility methods unsigned size() const { return ValuePtrs.size(); } void resize(unsigned N) { ValuePtrs.resize(N); } void push_back(Value *V) { ValuePtrs.emplace_back(V); } void clear() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); ValuePtrs.clear(); } Value *operator[](unsigned i) const { IGC_ASSERT(i < ValuePtrs.size()); return ValuePtrs[i]; } Value *back() const { return ValuePtrs.back(); } void pop_back() { ValuePtrs.pop_back(); } bool empty() const { return ValuePtrs.empty(); } void shrinkTo(unsigned N) { IGC_ASSERT(N <= size() && "Invalid shrinkTo request!"); ValuePtrs.resize(N); } Constant *getConstantFwdRef(unsigned Idx, Type *Ty); Value *getValueFwdRef(unsigned Idx, Type *Ty); void assignValue(Value *V, unsigned Idx); /// Once all constants are read, this method bulk resolves any forward /// references. void resolveConstantForwardRefs(); }; } // namespace llvm intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm7/000077500000000000000000000000001363533017100244015ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm7/BitcodeReader.cpp000066400000000000000000006374461363533017100276250ustar00rootroot00000000000000//===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "MetadataLoader.h" #include "ValueList.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalIndirectSymbol.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "common/LLVMWarningsPop.hpp" #include "BitcodeReader.h" #include "Probe.h" using namespace llvm; //===----------------------------------------------------------------------===// // upgrade bitcast to addrspacecast when necessary //===----------------------------------------------------------------------===// Instruction *upgradeBitCastInst(unsigned Opc, Value *V, Type *DestTy, Instruction *&Temp) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = V->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return CastInst::Create(Instruction::AddrSpaceCast, V, DestTy); } return nullptr; } Value *upgradeBitCastExpr(unsigned Opc, Constant *C, Type *DestTy) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = C->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return ConstantExpr::getAddrSpaceCast(C, DestTy); } return nullptr; } namespace { enum { SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; } // end anonymous namespace static Error error(const Twine &Message) { return make_error( Message, make_error_code(BitcodeError::CorruptedBitcode)); } /// Helper to read the header common to all bitcode files. static bool hasValidBitcodeHeader(BitstreamCursor &Stream) { // Sniff for the signature. if (!Stream.canSkipToPos(4) || Stream.Read(8) != 'B' || Stream.Read(8) != 'C' || Stream.Read(4) != 0x0 || Stream.Read(4) != 0xC || Stream.Read(4) != 0xE || Stream.Read(4) != 0xD) return false; return true; } static Expected initStream(MemoryBufferRef Buffer) { const unsigned char *BufPtr = (const unsigned char *)Buffer.getBufferStart(); const unsigned char *BufEnd = BufPtr + Buffer.getBufferSize(); if (Buffer.getBufferSize() & 3) return error("Invalid bitcode signature"); // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. if (isBitcodeWrapper(BufPtr, BufEnd)) if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) return error("Invalid bitcode wrapper header"); BitstreamCursor Stream(ArrayRef(BufPtr, BufEnd)); if (!hasValidBitcodeHeader(Stream)) return error("Invalid bitcode signature"); return std::move(Stream); } /// Convert a string from a record into an std::string, return true on failure. template static bool convertToString(ArrayRef Record, unsigned Idx, StrTy &Result) { if (Idx > Record.size()) return true; for (unsigned i = Idx, e = Record.size(); i != e; ++i) Result += (char)Record[i]; return false; } // Strip all the TBAA attachment for the module. static void stripTBAA(Module *M) { for (auto &F : *M) { if (F.isMaterializable()) continue; for (auto &I : instructions(F)) I.setMetadata(LLVMContext::MD_tbaa, nullptr); } } /// Read the "IDENTIFICATION_BLOCK_ID" block, do some basic enforcement on the /// "epoch" encoded in the bitcode, and return the producer name if any. static Expected readIdentificationBlock(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::IDENTIFICATION_BLOCK_ID)) return error("Invalid record"); // Read all the records. SmallVector Record; std::string ProducerIdentification; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { default: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ProducerIdentification; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: reject return error("Invalid value"); case bitc::IDENTIFICATION_CODE_STRING: // IDENTIFICATION: [strchr x N] convertToString(Record, 0, ProducerIdentification); break; case bitc::IDENTIFICATION_CODE_EPOCH: { // EPOCH: [epoch#] unsigned epoch = (unsigned)Record[0]; if (epoch != bitc::BITCODE_CURRENT_EPOCH) { return error( Twine("Incompatible epoch: Bitcode '") + Twine(epoch) + "' vs current: '" + Twine(bitc::BITCODE_CURRENT_EPOCH) + "'"); } } } } } static Expected readIdentificationCode(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { if (Stream.AtEndOfStream()) return ""; BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) return readIdentificationBlock(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } static Expected hasObjCCategoryInModule(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. switch (Stream.readRecord(Entry.ID, Record)) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Check for the i386 and other (x86_64, ARM) conventions if (S.find("__DATA,__objc_catlist") != std::string::npos || S.find("__OBJC,__category") != std::string::npos) return true; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } static Expected hasObjCCategory(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return hasObjCCategoryInModule(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } static Expected readModuleTriple(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; std::string Triple; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Triple; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. switch (Stream.readRecord(Entry.ID, Record)) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); Triple = S; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } static Expected readTriple(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ""; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return readModuleTriple(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } namespace { class BitcodeReaderBase { protected: BitcodeReaderBase(BitstreamCursor Stream, StringRef Strtab) : Stream(std::move(Stream)), Strtab(Strtab) { this->Stream.setBlockInfo(&BlockInfo); } BitstreamBlockInfo BlockInfo; BitstreamCursor Stream; StringRef Strtab; /// In version 2 of the bitcode we store names of global values and comdats in /// a string table rather than in the VST. bool UseStrtab = false; Expected parseVersionRecord(ArrayRef Record); /// If this module uses a string table, pop the reference to the string table /// and return the referenced string and the rest of the record. Otherwise /// just return the record itself. std::pair> readNameFromStrtab(ArrayRef Record); bool readBlockInfo(); // Contains an arbitrary and optional string identifying the bitcode producer std::string ProducerIdentification; Error error(const Twine &Message); }; } // end anonymous namespace Error BitcodeReaderBase::error(const Twine &Message) { std::string FullMsg = Message.str(); if (!ProducerIdentification.empty()) FullMsg += " (Producer: '" + ProducerIdentification + "' Reader: 'LLVM " + LLVM_VERSION_STRING "')"; return ::error(FullMsg); } Expected BitcodeReaderBase::parseVersionRecord(ArrayRef Record) { if (Record.empty()) return error("Invalid record"); unsigned ModuleVersion = Record[0]; if (ModuleVersion > 2) return error("Invalid value"); UseStrtab = ModuleVersion >= 2; return ModuleVersion; } std::pair> BitcodeReaderBase::readNameFromStrtab(ArrayRef Record) { if (!UseStrtab) return {"", Record}; // Invalid reference. Let the caller complain about the record being empty. if (Record[0] + Record[1] > Strtab.size()) return {"", {}}; return {StringRef(Strtab.data() + Record[0], Record[1]), Record.slice(2)}; } namespace { class BitcodeReader : public BitcodeReaderBase, public GVMaterializer { LLVMContext &Context; Module *TheModule = nullptr; // Next offset to start scanning for lazy parsing of function bodies. uint64_t NextUnreadBit = 0; // Last function offset found in the VST. uint64_t LastFunctionBlockBit = 0; bool SeenValueSymbolTable = false; uint64_t VSTOffset = 0; std::vector SectionTable; std::vector GCTable; std::vector TypeList; BitcodeReaderValueList ValueList; Optional MDLoader; std::vector ComdatList; SmallVector InstructionList; std::vector> GlobalInits; std::vector> IndirectSymbolInits; std::vector> FunctionPrefixes; std::vector> FunctionPrologues; std::vector> FunctionPersonalityFns; /// The set of attributes by index. Index zero in the file is for null, and /// is thus not represented here. As such all indices are off by one. std::vector MAttributes; /// The set of attribute groups. std::map MAttributeGroups; /// While parsing a function body, this is a list of the basic blocks for the /// function. std::vector FunctionBBs; // When reading the module header, this list is populated with functions that // have bodies later in the file. std::vector FunctionsWithBodies; // When intrinsic functions are encountered which require upgrading they are // stored here with their replacement function. using UpdatedIntrinsicMap = DenseMap; UpdatedIntrinsicMap UpgradedIntrinsics; // Intrinsics which were remangled because of types rename UpdatedIntrinsicMap RemangledIntrinsics; // Several operations happen after the module header has been read, but // before function bodies are processed. This keeps track of whether // we've done this yet. bool SeenFirstFunctionBody = false; /// When function bodies are initially scanned, this map contains info about /// where to find deferred function body in the stream. DenseMap DeferredFunctionInfo; /// When Metadata block is initially scanned when parsing the module, we may /// choose to defer parsing of the metadata. This vector contains info about /// which Metadata blocks are deferred. std::vector DeferredMetadataInfo; /// These are basic blocks forward-referenced by block addresses. They are /// inserted lazily into functions when they're loaded. The basic block ID is /// its index into the vector. DenseMap> BasicBlockFwdRefs; std::deque BasicBlockFwdRefQueue; /// Indicates that we are using a new encoding for instruction operands where /// most operands in the current FUNCTION_BLOCK are encoded relative to the /// instruction number, for a more compact encoding. Some instruction /// operands are not relative to the instruction ID: basic block numbers, and /// types. Once the old style function blocks have been phased out, we would /// not need this flag. bool UseRelativeIDs = false; /// True if all functions will be materialized, negating the need to process /// (e.g.) blockaddress forward references. bool WillMaterializeAllForwardRefs = false; bool StripDebugInfo = false; TBAAVerifier TBAAVerifyHelper; std::vector BundleTags; SmallVector SSIDs; public: BitcodeReader(BitstreamCursor Stream, StringRef Strtab, StringRef ProducerIdentification, LLVMContext &Context); Error materializeForwardReferencedFunctions(); Error materialize(GlobalValue *GV) override; Error materializeModule() override; std::vector getIdentifiedStructTypes() const override; /// \brief Main interface to parsing a bitcode buffer. /// \returns true if an error occurred. Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); static uint64_t decodeSignRotatedValue(uint64_t V); /// Materialize any deferred Metadata block. Error materializeMetadata() override; void setStripDebugInfo() override; private: std::vector IdentifiedStructTypes; StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); StructType *createIdentifiedStructType(LLVMContext &Context); Type *getTypeByID(unsigned ID); Value *getFnValueByID(unsigned ID, Type *Ty) { if (Ty && Ty->isMetadataTy()) return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); return ValueList.getValueFwdRef(ID, Ty); } Metadata *getFnMetadataByID(unsigned ID) { return MDLoader->getMetadataFwdRefOrLoad(ID); } BasicBlock *getBasicBlock(unsigned ID) const { if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID return FunctionBBs[ID]; } AttributeList getAttributes(unsigned i) const { if (i-1 < MAttributes.size()) return MAttributes[i-1]; return AttributeList(); } /// Read a value/type pair out of the specified record from slot 'Slot'. /// Increment Slot past the number of slots used in the record. Return true on /// failure. bool getValueTypePair(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Value *&ResVal) { if (Slot == Record.size()) return true; unsigned ValNo = (unsigned)Record[Slot++]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; if (ValNo < InstNum) { // If this is not a forward reference, just return the value we already // have. ResVal = getFnValueByID(ValNo, nullptr); return ResVal == nullptr; } if (Slot == Record.size()) return true; unsigned TypeNo = (unsigned)Record[Slot++]; ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo)); return ResVal == nullptr; } /// Read a value out of the specified record from slot 'Slot'. Increment Slot /// past the number of slots used by the value in the record. Return true if /// there is an error. bool popValue(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { if (getValue(Record, Slot, InstNum, Ty, ResVal)) return true; // All values currently take a single record slot. ++Slot; return false; } /// Like popValue, but does not increment the Slot number. bool getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { ResVal = getValue(Record, Slot, InstNum, Ty); return ResVal == nullptr; } /// Version of getValue that returns ResVal directly, or 0 if there is an /// error. Value *getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)Record[Slot]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Like getValue, but decodes signed VBRs. Value *getValueSigned(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)decodeSignRotatedValue(Record[Slot]); // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Converts alignment exponent (i.e. power of two (or zero)) to the /// corresponding alignment to use. If alignment is too large, returns /// a corresponding error code. Error parseAlignmentValue(uint64_t Exponent, unsigned &Alignment); Error parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind); Error parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata = false); Error parseComdatRecord(ArrayRef Record); Error parseGlobalVarRecord(ArrayRef Record); Error parseFunctionRecord(ArrayRef Record); Error parseGlobalIndirectSymbolRecord(unsigned BitCode, ArrayRef Record); Error parseAttributeBlock(); Error parseAttributeGroupBlock(); Error parseTypeTable(); Error parseTypeTableBody(); Error parseOperandBundleTags(); Error parseSyncScopeNames(); Expected recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT); void setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F, ArrayRef Record); Error parseValueSymbolTable(uint64_t Offset = 0); Error parseGlobalValueSymbolTable(); Error parseConstants(); Error rememberAndSkipFunctionBodies(); Error rememberAndSkipFunctionBody(); /// Save the positions of the Metadata blocks and skip parsing the blocks. Error rememberAndSkipMetadata(); Error typeCheckLoadStoreInst(Type *ValType, Type *PtrType); Error parseFunctionBody(Function *F); Error globalCleanup(); Error resolveGlobalAndIndirectSymbolInits(); Error parseUseLists(); Error findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator); SyncScope::ID getDecodedSyncScopeID(unsigned Val); }; /// Class to manage reading and parsing function summary index bitcode /// files/sections. class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase { /// The module index built during parsing. ModuleSummaryIndex &TheIndex; /// Indicates whether we have encountered a global value summary section /// yet during parsing. bool SeenGlobalValSummary = false; /// Indicates whether we have already parsed the VST, used for error checking. bool SeenValueSymbolTable = false; /// Set to the offset of the VST recorded in the MODULE_CODE_VSTOFFSET record. /// Used to enable on-demand parsing of the VST. uint64_t VSTOffset = 0; // Map to save ValueId to ValueInfo association that was recorded in the // ValueSymbolTable. It is used after the VST is parsed to convert // call graph edges read from the function summary from referencing // callees by their ValueId to using the ValueInfo instead, which is how // they are recorded in the summary index being built. // We save a GUID which refers to the same global as the ValueInfo, but // ignoring the linkage, i.e. for values other than local linkage they are // identical. DenseMap> ValueIdToValueInfoMap; /// Map populated during module path string table parsing, from the /// module ID to a string reference owned by the index's module /// path string table, used to correlate with combined index /// summary records. DenseMap ModuleIdMap; /// Original source file name recorded in a bitcode record. std::string SourceFileName; /// The string identifier given to this module by the client, normally the /// path to the bitcode file. StringRef ModulePath; /// For per-module summary indexes, the unique numerical identifier given to /// this module by the client. unsigned ModuleId; public: ModuleSummaryIndexBitcodeReader(BitstreamCursor Stream, StringRef Strtab, ModuleSummaryIndex &TheIndex, StringRef ModulePath, unsigned ModuleId); Error parseModule(); private: void setValueGUID(uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage, StringRef SourceFileName); Error parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap); std::vector makeRefList(ArrayRef Record); std::vector makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile); Error parseEntireSummary(unsigned ID); Error parseModuleStringTable(); std::pair getValueInfoFromValueId(unsigned ValueId); ModuleSummaryIndex::ModuleInfo *addThisModule(); }; } // end anonymous namespace #if 0 std::error_code llvm::errorToErrorCodeAndEmitErrors(LLVMContext &Ctx, Error Err) { if (Err) { std::error_code EC; handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { EC = EIB.convertToErrorCode(); Ctx.emitError(EIB.message()); }); return EC; } return std::error_code(); } #endif BitcodeReader::BitcodeReader(BitstreamCursor Stream, StringRef Strtab, StringRef ProducerIdentification, LLVMContext &Context) : BitcodeReaderBase(std::move(Stream), Strtab), Context(Context), ValueList(Context) { this->ProducerIdentification = ProducerIdentification; } Error BitcodeReader::materializeForwardReferencedFunctions() { if (WillMaterializeAllForwardRefs) return Error::success(); // Prevent recursion. WillMaterializeAllForwardRefs = true; while (!BasicBlockFwdRefQueue.empty()) { Function *F = BasicBlockFwdRefQueue.front(); BasicBlockFwdRefQueue.pop_front(); IGC_ASSERT(F && "Expected valid function"); if (!BasicBlockFwdRefs.count(F)) // Already materialized. continue; // Check for a function that isn't materializable to prevent an infinite // loop. When parsing a blockaddress stored in a global variable, there // isn't a trivial way to check if a function will have a body without a // linear search through FunctionsWithBodies, so just check it here. if (!F->isMaterializable()) return error("Never resolved function from blockaddress"); // Try to materialize F. if (Error Err = materialize(F)) return Err; } IGC_ASSERT(BasicBlockFwdRefs.empty() && "Function missing from queue"); // Reset state. WillMaterializeAllForwardRefs = false; return Error::success(); } //===----------------------------------------------------------------------===// // Helper functions to implement forward reference resolution, etc. //===----------------------------------------------------------------------===// static bool hasImplicitComdat(size_t Val) { switch (Val) { default: return false; case 1: // Old WeakAnyLinkage case 4: // Old LinkOnceAnyLinkage case 10: // Old WeakODRLinkage case 11: // Old LinkOnceODRLinkage return true; } } static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) { switch (Val) { default: // Map unknown/new linkages to external case 0: return GlobalValue::ExternalLinkage; case 2: return GlobalValue::AppendingLinkage; case 3: return GlobalValue::InternalLinkage; case 5: return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage case 6: return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage case 7: return GlobalValue::ExternalWeakLinkage; case 8: return GlobalValue::CommonLinkage; case 9: return GlobalValue::PrivateLinkage; case 12: return GlobalValue::AvailableExternallyLinkage; case 13: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage case 14: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateWeakLinkage case 15: return GlobalValue::ExternalLinkage; // Obsolete LinkOnceODRAutoHideLinkage case 1: // Old value with implicit comdat. case 16: return GlobalValue::WeakAnyLinkage; case 10: // Old value with implicit comdat. case 17: return GlobalValue::WeakODRLinkage; case 4: // Old value with implicit comdat. case 18: return GlobalValue::LinkOnceAnyLinkage; case 11: // Old value with implicit comdat. case 19: return GlobalValue::LinkOnceODRLinkage; } } static FunctionSummary::FFlags getDecodedFFlags(uint64_t RawFlags) { FunctionSummary::FFlags Flags; Flags.ReadNone = RawFlags & 0x1; Flags.ReadOnly = (RawFlags >> 1) & 0x1; Flags.NoRecurse = (RawFlags >> 2) & 0x1; Flags.ReturnDoesNotAlias = (RawFlags >> 3) & 0x1; return Flags; } /// Decode the flags for GlobalValue in the summary. static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags, uint64_t Version) { // Summary were not emitted before LLVM 3.9, we don't need to upgrade Linkage // like getDecodedLinkage() above. Any future change to the linkage enum and // to getDecodedLinkage() will need to be taken into account here as above. auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits RawFlags = RawFlags >> 4; bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3; // The Live flag wasn't introduced until version 3. For dead stripping // to work correctly on earlier versions, we must conservatively treat all // values as live. bool Live = (RawFlags & 0x2) || Version < 3; bool Local = (RawFlags & 0x4); return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live, Local); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { switch (Val) { default: // Map unknown visibilities to default. case 0: return GlobalValue::DefaultVisibility; case 1: return GlobalValue::HiddenVisibility; case 2: return GlobalValue::ProtectedVisibility; } } static GlobalValue::DLLStorageClassTypes getDecodedDLLStorageClass(unsigned Val) { switch (Val) { default: // Map unknown values to default. case 0: return GlobalValue::DefaultStorageClass; case 1: return GlobalValue::DLLImportStorageClass; case 2: return GlobalValue::DLLExportStorageClass; } } static bool getDecodedDSOLocal(unsigned Val) { switch(Val) { default: // Map unknown values to preemptable. case 0: return false; case 1: return true; } } static GlobalVariable::ThreadLocalMode getDecodedThreadLocalMode(unsigned Val) { switch (Val) { case 0: return GlobalVariable::NotThreadLocal; default: // Map unknown non-zero value to general dynamic. case 1: return GlobalVariable::GeneralDynamicTLSModel; case 2: return GlobalVariable::LocalDynamicTLSModel; case 3: return GlobalVariable::InitialExecTLSModel; case 4: return GlobalVariable::LocalExecTLSModel; } } static GlobalVariable::UnnamedAddr getDecodedUnnamedAddrType(unsigned Val) { switch (Val) { default: // Map unknown to UnnamedAddr::None. case 0: return GlobalVariable::UnnamedAddr::None; case 1: return GlobalVariable::UnnamedAddr::Global; case 2: return GlobalVariable::UnnamedAddr::Local; } } static int getDecodedCastOpcode(unsigned Val) { switch (Val) { default: return -1; case bitc::CAST_TRUNC : return Instruction::Trunc; case bitc::CAST_ZEXT : return Instruction::ZExt; case bitc::CAST_SEXT : return Instruction::SExt; case bitc::CAST_FPTOUI : return Instruction::FPToUI; case bitc::CAST_FPTOSI : return Instruction::FPToSI; case bitc::CAST_UITOFP : return Instruction::UIToFP; case bitc::CAST_SITOFP : return Instruction::SIToFP; case bitc::CAST_FPTRUNC : return Instruction::FPTrunc; case bitc::CAST_FPEXT : return Instruction::FPExt; case bitc::CAST_PTRTOINT: return Instruction::PtrToInt; case bitc::CAST_INTTOPTR: return Instruction::IntToPtr; case bitc::CAST_BITCAST : return Instruction::BitCast; case bitc::CAST_ADDRSPACECAST: return Instruction::AddrSpaceCast; } } static int getDecodedBinaryOpcode(unsigned Val, Type *Ty) { bool IsFP = Ty->isFPOrFPVectorTy(); // BinOps are only valid for int/fp or vector of int/fp types if (!IsFP && !Ty->isIntOrIntVectorTy()) return -1; switch (Val) { default: return -1; case bitc::BINOP_ADD: return IsFP ? Instruction::FAdd : Instruction::Add; case bitc::BINOP_SUB: return IsFP ? Instruction::FSub : Instruction::Sub; case bitc::BINOP_MUL: return IsFP ? Instruction::FMul : Instruction::Mul; case bitc::BINOP_UDIV: return IsFP ? -1 : Instruction::UDiv; case bitc::BINOP_SDIV: return IsFP ? Instruction::FDiv : Instruction::SDiv; case bitc::BINOP_UREM: return IsFP ? -1 : Instruction::URem; case bitc::BINOP_SREM: return IsFP ? Instruction::FRem : Instruction::SRem; case bitc::BINOP_SHL: return IsFP ? -1 : Instruction::Shl; case bitc::BINOP_LSHR: return IsFP ? -1 : Instruction::LShr; case bitc::BINOP_ASHR: return IsFP ? -1 : Instruction::AShr; case bitc::BINOP_AND: return IsFP ? -1 : Instruction::And; case bitc::BINOP_OR: return IsFP ? -1 : Instruction::Or; case bitc::BINOP_XOR: return IsFP ? -1 : Instruction::Xor; } } static AtomicRMWInst::BinOp getDecodedRMWOperation(unsigned Val) { switch (Val) { default: return AtomicRMWInst::BAD_BINOP; case bitc::RMW_XCHG: return AtomicRMWInst::Xchg; case bitc::RMW_ADD: return AtomicRMWInst::Add; case bitc::RMW_SUB: return AtomicRMWInst::Sub; case bitc::RMW_AND: return AtomicRMWInst::And; case bitc::RMW_NAND: return AtomicRMWInst::Nand; case bitc::RMW_OR: return AtomicRMWInst::Or; case bitc::RMW_XOR: return AtomicRMWInst::Xor; case bitc::RMW_MAX: return AtomicRMWInst::Max; case bitc::RMW_MIN: return AtomicRMWInst::Min; case bitc::RMW_UMAX: return AtomicRMWInst::UMax; case bitc::RMW_UMIN: return AtomicRMWInst::UMin; } } static AtomicOrdering getDecodedOrdering(unsigned Val) { switch (Val) { case bitc::ORDERING_NOTATOMIC: return AtomicOrdering::NotAtomic; case bitc::ORDERING_UNORDERED: return AtomicOrdering::Unordered; case bitc::ORDERING_MONOTONIC: return AtomicOrdering::Monotonic; case bitc::ORDERING_ACQUIRE: return AtomicOrdering::Acquire; case bitc::ORDERING_RELEASE: return AtomicOrdering::Release; case bitc::ORDERING_ACQREL: return AtomicOrdering::AcquireRelease; default: // Map unknown orderings to sequentially-consistent. case bitc::ORDERING_SEQCST: return AtomicOrdering::SequentiallyConsistent; } } static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) { switch (Val) { default: // Map unknown selection kinds to any. case bitc::COMDAT_SELECTION_KIND_ANY: return Comdat::Any; case bitc::COMDAT_SELECTION_KIND_EXACT_MATCH: return Comdat::ExactMatch; case bitc::COMDAT_SELECTION_KIND_LARGEST: return Comdat::Largest; case bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES: return Comdat::NoDuplicates; case bitc::COMDAT_SELECTION_KIND_SAME_SIZE: return Comdat::SameSize; } } static FastMathFlags getDecodedFastMathFlags(unsigned Val) { FastMathFlags FMF; if (0 != (Val & bitc::UnsafeAlgebra)) FMF.setFast(); if (0 != (Val & bitc::AllowReassoc)) FMF.setAllowReassoc(); if (0 != (Val & bitc::NoNaNs)) FMF.setNoNaNs(); if (0 != (Val & bitc::NoInfs)) FMF.setNoInfs(); if (0 != (Val & bitc::NoSignedZeros)) FMF.setNoSignedZeros(); if (0 != (Val & bitc::AllowReciprocal)) FMF.setAllowReciprocal(); if (0 != (Val & bitc::AllowContract)) FMF.setAllowContract(true); if (0 != (Val & bitc::ApproxFunc)) FMF.setApproxFunc(); return FMF; } static void upgradeDLLImportExportLinkage(GlobalValue *GV, unsigned Val) { switch (Val) { case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break; case 6: GV->setDLLStorageClass(GlobalValue::DLLExportStorageClass); break; } } Type *BitcodeReader::getTypeByID(unsigned ID) { // The type table size is always specified correctly. if (ID >= TypeList.size()) return nullptr; if (Type *Ty = TypeList[ID]) return Ty; // If we have a forward reference, the only possible case is when it is to a // named struct. Just create a placeholder for now. return TypeList[ID] = createIdentifiedStructType(Context); } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context, StringRef Name) { auto *Ret = StructType::create(Context, Name); IdentifiedStructTypes.push_back(Ret); return Ret; } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) { auto *Ret = StructType::create(Context); IdentifiedStructTypes.push_back(Ret); return Ret; } //===----------------------------------------------------------------------===// // Functions for parsing blocks from the bitcode file //===----------------------------------------------------------------------===// static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { switch (Val) { case Attribute::EndAttrKinds: llvm_unreachable("Synthetic enumerators which should never get here"); case Attribute::None: return 0; case Attribute::ZExt: return 1 << 0; case Attribute::SExt: return 1 << 1; case Attribute::NoReturn: return 1 << 2; case Attribute::InReg: return 1 << 3; case Attribute::StructRet: return 1 << 4; case Attribute::NoUnwind: return 1 << 5; case Attribute::NoAlias: return 1 << 6; case Attribute::ByVal: return 1 << 7; case Attribute::Nest: return 1 << 8; case Attribute::ReadNone: return 1 << 9; case Attribute::ReadOnly: return 1 << 10; case Attribute::NoInline: return 1 << 11; case Attribute::AlwaysInline: return 1 << 12; case Attribute::OptimizeForSize: return 1 << 13; case Attribute::StackProtect: return 1 << 14; case Attribute::StackProtectReq: return 1 << 15; case Attribute::Alignment: return 31 << 16; case Attribute::NoCapture: return 1 << 21; case Attribute::NoRedZone: return 1 << 22; case Attribute::NoImplicitFloat: return 1 << 23; case Attribute::Naked: return 1 << 24; case Attribute::InlineHint: return 1 << 25; case Attribute::StackAlignment: return 7 << 26; case Attribute::ReturnsTwice: return 1 << 29; case Attribute::UWTable: return 1 << 30; case Attribute::NonLazyBind: return 1U << 31; case Attribute::SanitizeAddress: return 1ULL << 32; case Attribute::MinSize: return 1ULL << 33; case Attribute::NoDuplicate: return 1ULL << 34; case Attribute::StackProtectStrong: return 1ULL << 35; case Attribute::SanitizeThread: return 1ULL << 36; case Attribute::SanitizeMemory: return 1ULL << 37; case Attribute::NoBuiltin: return 1ULL << 38; case Attribute::Returned: return 1ULL << 39; case Attribute::Cold: return 1ULL << 40; case Attribute::Builtin: return 1ULL << 41; case Attribute::OptimizeNone: return 1ULL << 42; case Attribute::InAlloca: return 1ULL << 43; case Attribute::NonNull: return 1ULL << 44; case Attribute::JumpTable: return 1ULL << 45; case Attribute::Convergent: return 1ULL << 46; case Attribute::SafeStack: return 1ULL << 47; case Attribute::NoRecurse: return 1ULL << 48; case Attribute::InaccessibleMemOnly: return 1ULL << 49; case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50; case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; case Attribute::WriteOnly: return 1ULL << 53; case Attribute::Speculatable: return 1ULL << 54; case Attribute::StrictFP: return 1ULL << 55; case Attribute::SanitizeHWAddress: return 1ULL << 56; case Attribute::NoCfCheck: return 1ULL << 57; case Attribute::OptForFuzzing: return 1ULL << 58; case Attribute::ShadowCallStack: return 1ULL << 58; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; case Attribute::DereferenceableOrNull: llvm_unreachable("dereferenceable_or_null attribute not supported in raw " "format"); break; case Attribute::ArgMemOnly: llvm_unreachable("argmemonly attribute not supported in raw format"); break; case Attribute::AllocSize: llvm_unreachable("allocsize not supported in raw format"); break; default: llvm_unreachable("Unsupported attribute type"); break; //return 0; } } static void addRawAttributeValue(AttrBuilder &B, uint64_t Val) { if (!Val) return; for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; I = Attribute::AttrKind(I + 1)) { if (I == Attribute::Dereferenceable || I == Attribute::DereferenceableOrNull || I == Attribute::ArgMemOnly || I == Attribute::AllocSize) continue; if (uint64_t A = (Val & getRawAttributeMask(I))) { if (I == Attribute::Alignment) B.addAlignmentAttr(1ULL << ((A >> 16) - 1)); else if (I == Attribute::StackAlignment) B.addStackAlignmentAttr(1ULL << ((A >> 26)-1)); else B.addAttribute(I); } } } /// \brief This fills an AttrBuilder object with the LLVM attributes that have /// been decoded from the given integer. This function must stay in sync with /// 'encodeLLVMAttributesForBitcode'. static void decodeLLVMAttributesForBitcode(AttrBuilder &B, uint64_t EncodedAttrs) { // FIXME: Remove in 4.0. // The alignment is stored as a 16-bit raw value from bits 31--16. We shift // the bits above 31 down by 11 bits. unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; IGC_ASSERT((!Alignment || isPowerOf2_32(Alignment)) && "Alignment must be a power of two."); if (Alignment) B.addAlignmentAttr(Alignment); addRawAttributeValue(B, ((EncodedAttrs & (0xfffffULL << 32)) >> 11) | (EncodedAttrs & 0xffff)); } Error BitcodeReader::parseAttributeBlock() { if (Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID)) return error("Invalid record"); if (!MAttributes.empty()) return error("Invalid multiple blocks"); SmallVector Record; SmallVector Attrs; // Read all the records. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_CODE_ENTRY_OLD: // ENTRY: [paramidx0, attr0, ...] // FIXME: Remove in 4.0. if (Record.size() & 1) return error("Invalid record"); for (unsigned i = 0, e = Record.size(); i != e; i += 2) { AttrBuilder B; decodeLLVMAttributesForBitcode(B, Record[i+1]); Attrs.push_back(AttributeList::get(Context, Record[i], B)); } MAttributes.push_back(AttributeList::get(Context, Attrs)); Attrs.clear(); break; case bitc::PARAMATTR_CODE_ENTRY: // ENTRY: [attrgrp0, attrgrp1, ...] for (unsigned i = 0, e = Record.size(); i != e; ++i) Attrs.push_back(MAttributeGroups[Record[i]]); MAttributes.push_back(AttributeList::get(Context, Attrs)); Attrs.clear(); break; } } } // Returns Attribute::None on unrecognized codes. static Attribute::AttrKind getAttrFromCode(uint64_t Code) { switch (Code) { default: return Attribute::None; case bitc::ATTR_KIND_ALIGNMENT: return Attribute::Alignment; case bitc::ATTR_KIND_ALWAYS_INLINE: return Attribute::AlwaysInline; case bitc::ATTR_KIND_ARGMEMONLY: return Attribute::ArgMemOnly; case bitc::ATTR_KIND_BUILTIN: return Attribute::Builtin; case bitc::ATTR_KIND_BY_VAL: return Attribute::ByVal; case bitc::ATTR_KIND_IN_ALLOCA: return Attribute::InAlloca; case bitc::ATTR_KIND_COLD: return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: return Attribute::InaccessibleMemOnly; case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: return Attribute::InaccessibleMemOrArgMemOnly; case bitc::ATTR_KIND_INLINE_HINT: return Attribute::InlineHint; case bitc::ATTR_KIND_IN_REG: return Attribute::InReg; case bitc::ATTR_KIND_JUMP_TABLE: return Attribute::JumpTable; case bitc::ATTR_KIND_MIN_SIZE: return Attribute::MinSize; case bitc::ATTR_KIND_NAKED: return Attribute::Naked; case bitc::ATTR_KIND_NEST: return Attribute::Nest; case bitc::ATTR_KIND_NO_ALIAS: return Attribute::NoAlias; case bitc::ATTR_KIND_NO_BUILTIN: return Attribute::NoBuiltin; case bitc::ATTR_KIND_NO_CAPTURE: return Attribute::NoCapture; case bitc::ATTR_KIND_NO_DUPLICATE: return Attribute::NoDuplicate; case bitc::ATTR_KIND_NO_IMPLICIT_FLOAT: return Attribute::NoImplicitFloat; case bitc::ATTR_KIND_NO_INLINE: return Attribute::NoInline; case bitc::ATTR_KIND_NO_RECURSE: return Attribute::NoRecurse; case bitc::ATTR_KIND_NON_LAZY_BIND: return Attribute::NonLazyBind; case bitc::ATTR_KIND_NON_NULL: return Attribute::NonNull; case bitc::ATTR_KIND_DEREFERENCEABLE: return Attribute::Dereferenceable; case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: return Attribute::DereferenceableOrNull; case bitc::ATTR_KIND_ALLOC_SIZE: return Attribute::AllocSize; case bitc::ATTR_KIND_NO_RED_ZONE: return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: return Attribute::NoReturn; case bitc::ATTR_KIND_NO_UNWIND: return Attribute::NoUnwind; case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: return Attribute::OptimizeForSize; case bitc::ATTR_KIND_OPTIMIZE_NONE: return Attribute::OptimizeNone; case bitc::ATTR_KIND_READ_NONE: return Attribute::ReadNone; case bitc::ATTR_KIND_READ_ONLY: return Attribute::ReadOnly; case bitc::ATTR_KIND_RETURNED: return Attribute::Returned; case bitc::ATTR_KIND_RETURNS_TWICE: return Attribute::ReturnsTwice; case bitc::ATTR_KIND_S_EXT: return Attribute::SExt; case bitc::ATTR_KIND_SPECULATABLE: return Attribute::Speculatable; case bitc::ATTR_KIND_STACK_ALIGNMENT: return Attribute::StackAlignment; case bitc::ATTR_KIND_STACK_PROTECT: return Attribute::StackProtect; case bitc::ATTR_KIND_STACK_PROTECT_REQ: return Attribute::StackProtectReq; case bitc::ATTR_KIND_STACK_PROTECT_STRONG: return Attribute::StackProtectStrong; case bitc::ATTR_KIND_SAFESTACK: return Attribute::SafeStack; case bitc::ATTR_KIND_STRICT_FP: return Attribute::StrictFP; case bitc::ATTR_KIND_STRUCT_RET: return Attribute::StructRet; case bitc::ATTR_KIND_SANITIZE_ADDRESS: return Attribute::SanitizeAddress; case bitc::ATTR_KIND_SANITIZE_HWADDRESS: return Attribute::SanitizeHWAddress; case bitc::ATTR_KIND_SANITIZE_THREAD: return Attribute::SanitizeThread; case bitc::ATTR_KIND_SANITIZE_MEMORY: return Attribute::SanitizeMemory; case bitc::ATTR_KIND_SWIFT_ERROR: return Attribute::SwiftError; case bitc::ATTR_KIND_SWIFT_SELF: return Attribute::SwiftSelf; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; case bitc::ATTR_KIND_WRITEONLY: return Attribute::WriteOnly; case bitc::ATTR_KIND_Z_EXT: return Attribute::ZExt; } } Error BitcodeReader::parseAlignmentValue(uint64_t Exponent, unsigned &Alignment) { // Note: Alignment in bitcode files is incremented by 1, so that zero // can be used for default alignment. if (Exponent > Value::MaxAlignmentExponent + 1) return error("Invalid alignment value"); Alignment = (1 << static_cast(Exponent)) >> 1; return Error::success(); } Error BitcodeReader::parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind) { *Kind = getAttrFromCode(Code); if (*Kind == Attribute::None) return error("Unknown attribute kind (" + Twine(Code) + ")"); return Error::success(); } Error BitcodeReader::parseAttributeGroupBlock() { if (Stream.EnterSubBlock(bitc::PARAMATTR_GROUP_BLOCK_ID)) return error("Invalid record"); if (!MAttributeGroups.empty()) return error("Invalid multiple blocks"); SmallVector Record; // Read all the records. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_GRP_CODE_ENTRY: { // ENTRY: [grpid, idx, a0, a1, ...] if (Record.size() < 3) return error("Invalid record"); uint64_t GrpID = Record[0]; uint64_t Idx = Record[1]; // Index of the object this attribute refers to. AttrBuilder B; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Record[i] == 0) { // Enum attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; B.addAttribute(Kind); } else if (Record[i] == 1) { // Integer attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; if (Kind == Attribute::Alignment) B.addAlignmentAttr(Record[++i]); else if (Kind == Attribute::StackAlignment) B.addStackAlignmentAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); else if (Kind == Attribute::DereferenceableOrNull) B.addDereferenceableOrNullAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); } else { // String attribute IGC_ASSERT((Record[i] == 3 || Record[i] == 4) && "Invalid attribute group entry"); bool HasValue = (Record[i++] == 4); SmallString<64> KindStr; SmallString<64> ValStr; while (Record[i] != 0 && i != e) KindStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Kind string not null terminated"); if (HasValue) { // Has a value associated with it. ++i; // Skip the '0' that terminates the "kind" string. while (Record[i] != 0 && i != e) ValStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Value string not null terminated"); } B.addAttribute(KindStr.str(), ValStr.str()); } } MAttributeGroups[GrpID] = AttributeList::get(Context, Idx, B); break; } } } } Error BitcodeReader::parseTypeTable() { if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW)) return error("Invalid record"); return parseTypeTableBody(); } Error BitcodeReader::parseTypeTableBody() { if (!TypeList.empty()) return error("Invalid multiple blocks"); SmallVector Record; unsigned NumRecords = 0; SmallString<64> TypeName; // Read all the records for this type table. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NumRecords != TypeList.size()) return error("Malformed block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *ResultTy = nullptr; switch (Stream.readRecord(Entry.ID, Record)) { default: return error("Invalid value"); case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] // TYPE_CODE_NUMENTRY contains a count of the number of types in the // type list. This allows us to reserve space. if (Record.size() < 1) return error("Invalid record"); TypeList.resize(Record[0]); continue; case bitc::TYPE_CODE_VOID: // VOID ResultTy = Type::getVoidTy(Context); break; case bitc::TYPE_CODE_HALF: // HALF ResultTy = Type::getHalfTy(Context); break; case bitc::TYPE_CODE_FLOAT: // FLOAT ResultTy = Type::getFloatTy(Context); break; case bitc::TYPE_CODE_DOUBLE: // DOUBLE ResultTy = Type::getDoubleTy(Context); break; case bitc::TYPE_CODE_X86_FP80: // X86_FP80 ResultTy = Type::getX86_FP80Ty(Context); break; case bitc::TYPE_CODE_FP128: // FP128 ResultTy = Type::getFP128Ty(Context); break; case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 ResultTy = Type::getPPC_FP128Ty(Context); break; case bitc::TYPE_CODE_LABEL: // LABEL ResultTy = Type::getLabelTy(Context); break; case bitc::TYPE_CODE_METADATA: // METADATA ResultTy = Type::getMetadataTy(Context); break; case bitc::TYPE_CODE_X86_MMX: // X86_MMX ResultTy = Type::getX86_MMXTy(Context); break; case bitc::TYPE_CODE_TOKEN: // TOKEN ResultTy = Type::getTokenTy(Context); break; case bitc::TYPE_CODE_INTEGER: { // INTEGER: [width] if (Record.size() < 1) return error("Invalid record"); uint64_t NumBits = Record[0]; if (NumBits < IntegerType::MIN_INT_BITS || NumBits > IntegerType::MAX_INT_BITS) return error("Bitwidth for integer type out of range"); ResultTy = IntegerType::get(Context, NumBits); break; } case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or // [pointee type, address space] if (Record.size() < 1) return error("Invalid record"); unsigned AddressSpace = 0; if (Record.size() == 2) AddressSpace = Record[1]; ResultTy = getTypeByID(Record[0]); if (!ResultTy || !PointerType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = PointerType::get(ResultTy, AddressSpace); break; } case bitc::TYPE_CODE_FUNCTION_OLD: { // FIXME: attrid is dead, remove it in LLVM 4.0 // FUNCTION: [vararg, attrid, retty, paramty x N] if (Record.size() < 3) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 3, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) ArgTys.push_back(T); else break; } ResultTy = getTypeByID(Record[2]); if (!ResultTy || ArgTys.size() < Record.size()-3) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_FUNCTION: { // FUNCTION: [vararg, retty, paramty x N] if (Record.size() < 2) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) { if (!FunctionType::isValidArgumentType(T)) return error("Invalid function argument type"); ArgTys.push_back(T); } else break; } ResultTy = getTypeByID(Record[1]); if (!ResultTy || ArgTys.size() < Record.size()-2) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid type"); ResultTy = StructType::get(Context, EltTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N] if (convertToString(Record, 0, TypeName)) return error("Invalid record"); continue; case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid record"); Res->setBody(EltTys, Record[0]); ResultTy = Res; break; } case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: [] if (Record.size() != 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct with no body. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); ResultTy = Res; break; } case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !ArrayType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = ArrayType::get(ResultTy, Record[0]); break; case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); if (Record[0] == 0) return error("Invalid vector length"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !StructType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = VectorType::get(ResultTy, Record[0]); break; } if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); if (TypeList[NumRecords]) return error( "Invalid TYPE table: Only named structs can be forward referenced"); IGC_ASSERT(ResultTy && "Didn't read a type?"); TypeList[NumRecords++] = ResultTy; } } Error BitcodeReader::parseOperandBundleTags() { if (Stream.EnterSubBlock(bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID)) return error("Invalid record"); if (!BundleTags.empty()) return error("Invalid multiple blocks"); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Tags are implicitly mapped to integers by their order. if (Stream.readRecord(Entry.ID, Record) != bitc::OPERAND_BUNDLE_TAG) return error("Invalid record"); // OPERAND_BUNDLE_TAG: [strchr x N] BundleTags.emplace_back(); if (convertToString(Record, 0, BundleTags.back())) return error("Invalid record"); Record.clear(); } } Error BitcodeReader::parseSyncScopeNames() { if (Stream.EnterSubBlock(bitc::SYNC_SCOPE_NAMES_BLOCK_ID)) return error("Invalid record"); if (!SSIDs.empty()) return error("Invalid multiple synchronization scope names blocks"); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (SSIDs.empty()) return error("Invalid empty synchronization scope names block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Synchronization scope names are implicitly mapped to synchronization // scope IDs by their order. if (Stream.readRecord(Entry.ID, Record) != bitc::SYNC_SCOPE_NAME) return error("Invalid record"); SmallString<16> SSN; if (convertToString(Record, 0, SSN)) return error("Invalid record"); SSIDs.push_back(Context.getOrInsertSyncScopeID(SSN)); Record.clear(); } } /// Associate a value with its name from the given index in the provided record. Expected BitcodeReader::recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT) { SmallString<128> ValueName; if (convertToString(Record, NameIndex, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; if (ValueID >= ValueList.size() || !ValueList[ValueID]) return error("Invalid record"); Value *V = ValueList[ValueID]; StringRef NameStr(ValueName.data(), ValueName.size()); if (NameStr.find_first_of(0) != StringRef::npos) return error("Invalid value name"); V->setName(NameStr); auto *GO = dyn_cast(V); if (GO) { if (GO->getComdat() == reinterpret_cast(1)) { if (TT.supportsCOMDAT()) GO->setComdat(TheModule->getOrInsertComdat(V->getName())); else GO->setComdat(nullptr); } } return V; } /// Helper to note and return the current location, and jump to the given /// offset. static uint64_t jumpToValueSymbolTable(uint64_t Offset, BitstreamCursor &Stream) { // Save the current parsing location so we can jump back at the end // of the VST read. uint64_t CurrentBit = Stream.GetCurrentBitNo(); Stream.JumpToBit(Offset * 32); #ifndef NDEBUG // Do some checking if we are in debug mode. BitstreamEntry Entry = Stream.advance(); IGC_ASSERT(Entry.Kind == BitstreamEntry::SubBlock); IGC_ASSERT(Entry.ID == bitc::VALUE_SYMTAB_BLOCK_ID); #else // In NDEBUG mode ignore the output so we don't get an unused variable // warning. Stream.advance(); #endif return CurrentBit; } void BitcodeReader::setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F, ArrayRef Record) { // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. uint64_t FuncWordOffset = Record[1] - 1; uint64_t FuncBitOffset = FuncWordOffset * 32; DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta; // Set the LastFunctionBlockBit to point to the last function block. // Later when parsing is resumed after function materialization, // we can simply skip that last function block. if (FuncBitOffset > LastFunctionBlockBit) LastFunctionBlockBit = FuncBitOffset; } /// Read a new-style GlobalValue symbol table. Error BitcodeReader::parseGlobalValueSymbolTable() { unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: break; } Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { case bitc::VST_CODE_FNENTRY: // [valueid, offset] setDeferredFunctionInfo(FuncBitcodeOffsetDelta, cast(ValueList[Record[0]]), Record); break; } } } /// Parse the value symbol table at either the current parsing location or /// at the given bit offset if provided. Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) { uint64_t CurrentBit; // Pass in the Offset to distinguish between calling for the module-level // VST (where we want to jump to the VST offset) and the function-level // VST (where we don't). if (Offset > 0) { CurrentBit = jumpToValueSymbolTable(Offset, Stream); // If this module uses a string table, read this as a module-level VST. if (UseStrtab) { if (Error Err = parseGlobalValueSymbolTable()) return Err; Stream.JumpToBit(CurrentBit); return Error::success(); } // Otherwise, the VST will be in a similar format to a function-level VST, // and will contain symbol names. } // Compute the delta between the bitcode indices in the VST (the word offset // to the word-aligned ENTER_SUBBLOCK for the function block, and that // expected by the lazy reader. The reader's EnterSubBlock expects to have // already read the ENTER_SUBBLOCK code (size getAbbrevIDWidth) and BlockID // (size BlockIDWidth). Note that we access the stream's AbbrevID width here // just before entering the VST subblock because: 1) the EnterSubBlock // changes the AbbrevID width; 2) the VST block is nested within the same // outer MODULE_BLOCK as the FUNCTION_BLOCKs and therefore have the same // AbbrevID width before calling EnterSubBlock; and 3) when we want to // jump to the FUNCTION_BLOCK using this offset later, we don't want // to rely on the stream's AbbrevID width being that of the MODULE_BLOCK. unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; Triple TT(TheModule->getTargetTriple()); // Read all the records for this value table. SmallString<128> ValueName; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (Offset > 0) Stream.JumpToBit(CurrentBit); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: unknown type. break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] Expected ValOrErr = recordValue(Record, 1, TT); if (Error Err = ValOrErr.takeError()) return Err; ValOrErr.get(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] Expected ValOrErr = recordValue(Record, 2, TT); if (Error Err = ValOrErr.takeError()) return Err; Value *V = ValOrErr.get(); // Ignore function offsets emitted for aliases of functions in older // versions of LLVM. if (auto *F = dyn_cast(V)) setDeferredFunctionInfo(FuncBitcodeOffsetDelta, F, Record); break; } case bitc::VST_CODE_BBENTRY: { if (convertToString(Record, 1, ValueName)) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[0]); if (!BB) return error("Invalid record"); BB->setName(StringRef(ValueName.data(), ValueName.size())); ValueName.clear(); break; } } } } /// Decode a signed value stored with the sign bit in the LSB for dense VBR /// encoding. uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) { if ((V & 1) == 0) return V >> 1; if (V != 1) return -(V >> 1); // There is no such thing as -0 with integers. "-0" really means MININT. return 1ULL << 63; } /// Resolve all of the initializers for global values and aliases that we can. Error BitcodeReader::resolveGlobalAndIndirectSymbolInits() { std::vector> GlobalInitWorklist; std::vector> IndirectSymbolInitWorklist; std::vector> FunctionPrefixWorklist; std::vector> FunctionPrologueWorklist; std::vector> FunctionPersonalityFnWorklist; GlobalInitWorklist.swap(GlobalInits); IndirectSymbolInitWorklist.swap(IndirectSymbolInits); FunctionPrefixWorklist.swap(FunctionPrefixes); FunctionPrologueWorklist.swap(FunctionPrologues); FunctionPersonalityFnWorklist.swap(FunctionPersonalityFns); while (!GlobalInitWorklist.empty()) { unsigned ValID = GlobalInitWorklist.back().second; if (ValID >= ValueList.size()) { // Not ready to resolve this yet, it requires something later in the file. GlobalInits.push_back(GlobalInitWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) GlobalInitWorklist.back().first->setInitializer(C); else return error("Expected a constant"); } GlobalInitWorklist.pop_back(); } while (!IndirectSymbolInitWorklist.empty()) { unsigned ValID = IndirectSymbolInitWorklist.back().second; if (ValID >= ValueList.size()) { IndirectSymbolInits.push_back(IndirectSymbolInitWorklist.back()); } else { Constant *C = dyn_cast_or_null(ValueList[ValID]); if (!C) return error("Expected a constant"); GlobalIndirectSymbol *GIS = IndirectSymbolInitWorklist.back().first; if (isa(GIS) && C->getType() != GIS->getType()) return error("Alias and aliasee types don't match"); GIS->setIndirectSymbol(C); } IndirectSymbolInitWorklist.pop_back(); } while (!FunctionPrefixWorklist.empty()) { unsigned ValID = FunctionPrefixWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrefixes.push_back(FunctionPrefixWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrefixWorklist.back().first->setPrefixData(C); else return error("Expected a constant"); } FunctionPrefixWorklist.pop_back(); } while (!FunctionPrologueWorklist.empty()) { unsigned ValID = FunctionPrologueWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrologues.push_back(FunctionPrologueWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrologueWorklist.back().first->setPrologueData(C); else return error("Expected a constant"); } FunctionPrologueWorklist.pop_back(); } while (!FunctionPersonalityFnWorklist.empty()) { unsigned ValID = FunctionPersonalityFnWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPersonalityFns.push_back(FunctionPersonalityFnWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPersonalityFnWorklist.back().first->setPersonalityFn(C); else return error("Expected a constant"); } FunctionPersonalityFnWorklist.pop_back(); } return Error::success(); } static APInt readWideAPInt(ArrayRef Vals, unsigned TypeBits) { SmallVector Words(Vals.size()); transform(Vals, Words.begin(), BitcodeReader::decodeSignRotatedValue); return APInt(TypeBits, Words); } Error BitcodeReader::parseConstants() { if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this value table. Type *CurTy = Type::getInt32Ty(Context); unsigned NextCstNo = ValueList.size(); while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NextCstNo != ValueList.size()) return error("Invalid constant reference"); // Once all the constants have been read, go through and resolve forward // references. ValueList.resolveConstantForwardRefs(); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *VoidType = Type::getVoidTy(Context); Value *V = nullptr; unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: unknown constant case bitc::CST_CODE_UNDEF: // UNDEF V = UndefValue::get(CurTy); break; case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid] if (Record.empty()) return error("Invalid record"); if (Record[0] >= TypeList.size() || !TypeList[Record[0]]) return error("Invalid record"); if (TypeList[Record[0]] == VoidType) return error("Invalid constant type"); CurTy = TypeList[Record[0]]; continue; // Skip the ValueList manipulation. case bitc::CST_CODE_NULL: // NULL V = Constant::getNullValue(CurTy); break; case bitc::CST_CODE_INTEGER: // INTEGER: [intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0])); break; case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); APInt VInt = readWideAPInt(Record, cast(CurTy)->getBitWidth()); V = ConstantInt::get(Context, VInt); break; } case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval] if (Record.empty()) return error("Invalid record"); if (CurTy->isHalfTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf(), APInt(16, (uint16_t)Record[0]))); else if (CurTy->isFloatTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle(), APInt(32, (uint32_t)Record[0]))); else if (CurTy->isDoubleTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble(), APInt(64, Record[0]))); else if (CurTy->isX86_FP80Ty()) { // Bits are not stored the same way as a normal i80 APInt, compensate. uint64_t Rearrange[2]; Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16); Rearrange[1] = Record[0] >> 48; V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended(), APInt(80, Rearrange))); } else if (CurTy->isFP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad(), APInt(128, Record))); else if (CurTy->isPPC_FP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble(), APInt(128, Record))); else V = UndefValue::get(CurTy); break; } case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number] if (Record.empty()) return error("Invalid record"); unsigned Size = Record.size(); SmallVector Elts; if (StructType *STy = dyn_cast(CurTy)) { for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); } else if (ArrayType *ATy = dyn_cast(CurTy)) { Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantArray::get(ATy, Elts); } else if (VectorType *VTy = dyn_cast(CurTy)) { Type *EltTy = VTy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantVector::get(Elts); } else { V = UndefValue::get(CurTy); } break; } case bitc::CST_CODE_STRING: // STRING: [values] case bitc::CST_CODE_CSTRING: { // CSTRING: [values] if (Record.empty()) return error("Invalid record"); SmallString<16> Elts(Record.begin(), Record.end()); V = ConstantDataArray::getString(Context, Elts, BitCode == bitc::CST_CODE_CSTRING); break; } case bitc::CST_CODE_DATA: {// DATA: [n x value] if (Record.empty()) return error("Invalid record"); Type *EltTy = cast(CurTy)->getElementType(); if (EltTy->isIntegerTy(8)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(16)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(32)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(64)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isHalfTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isFloatTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isDoubleTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else { return error("Invalid type for value"); } break; } case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[0], CurTy); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown binop. } else { Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy); unsigned Flags = 0; if (Record.size() >= 4) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoSignedWrap; if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoUnsignedWrap; } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[3] & (1 << bitc::PEO_EXACT)) Flags |= SDivOperator::IsExact; } } V = ConstantExpr::get(Opc, LHS, RHS, Flags); } break; } case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedCastOpcode(Record[0]); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown cast. } else { Type *OpTy = getTypeByID(Record[1]); if (!OpTy) return error("Invalid record"); Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy); V = upgradeBitCastExpr(Opc, Op, CurTy); if (!V) V = ConstantExpr::getCast(Opc, Op, CurTy); } break; } case bitc::CST_CODE_CE_INBOUNDS_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX: { // [ty, flags, n x // operands] unsigned OpNum = 0; Type *PointeeType = nullptr; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX || Record.size() % 2) PointeeType = getTypeByID(Record[OpNum++]); bool InBounds = false; Optional InRangeIndex; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX) { uint64_t Op = Record[OpNum++]; InBounds = Op & 1; InRangeIndex = Op >> 1; } else if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP) InBounds = true; SmallVector Elts; while (OpNum != Record.size()) { Type *ElTy = getTypeByID(Record[OpNum++]); if (!ElTy) return error("Invalid record"); Elts.push_back(ValueList.getConstantFwdRef(Record[OpNum++], ElTy)); } if (PointeeType && PointeeType != cast(Elts[0]->getType()->getScalarType()) ->getElementType()) return error("Explicit gep operator type does not match pointee type " "of pointer operand"); if (Elts.size() < 1) return error("Invalid gep with no operands"); ArrayRef Indices(Elts.begin() + 1, Elts.end()); V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices, InBounds, InRangeIndex); break; } case bitc::CST_CODE_CE_SELECT: { // CE_SELECT: [opval#, opval#, opval#] if (Record.size() < 3) return error("Invalid record"); Type *SelectorTy = Type::getInt1Ty(Context); // The selector might be an i1 or an // Get the type from the ValueList before getting a forward ref. if (VectorType *VTy = dyn_cast(CurTy)) if (Value *V = ValueList[Record[0]]) if (SelectorTy != V->getType()) SelectorTy = VectorType::get(SelectorTy, VTy->getNumElements()); V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0], SelectorTy), ValueList.getConstantFwdRef(Record[1],CurTy), ValueList.getConstantFwdRef(Record[2],CurTy)); break; } case bitc::CST_CODE_CE_EXTRACTELT : { // CE_EXTRACTELT: [opty, opval, opty, opval] if (Record.size() < 3) return error("Invalid record"); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op1 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op1) return error("Invalid record"); V = ConstantExpr::getExtractElement(Op0, Op1); break; } case bitc::CST_CODE_CE_INSERTELT : { // CE_INSERTELT: [opval, opval, opty, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy->getElementType()); Constant *Op2 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op2 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op2) return error("Invalid record"); V = ConstantExpr::getInsertElement(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), OpTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval] VectorType *RTy = dyn_cast(CurTy); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (Record.size() < 4 || !RTy || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), RTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred] if (Record.size() < 4) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); if (OpTy->isFPOrFPVectorTy()) V = ConstantExpr::getFCmp(Record[3], Op0, Op1); else V = ConstantExpr::getICmp(Record[3], Op0, Op1); break; } // This maintains backward compatibility, pre-asm dialect keywords. // FIXME: Remove with the 4.0 release. case bitc::CST_CODE_INLINEASM_OLD: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = Record[0] >> 1; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; PointerType *PTy = cast(CurTy); V = InlineAsm::get(cast(PTy->getElementType()), AsmStr, ConstrStr, HasSideEffects, IsAlignStack); break; } // This version adds support for the asm dialect keywords (e.g., // inteldialect). case bitc::CST_CODE_INLINEASM: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = (Record[0] >> 1) & 1; unsigned AsmDialect = Record[0] >> 2; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; PointerType *PTy = cast(CurTy); V = InlineAsm::get(cast(PTy->getElementType()), AsmStr, ConstrStr, HasSideEffects, IsAlignStack, InlineAsm::AsmDialect(AsmDialect)); break; } case bitc::CST_CODE_BLOCKADDRESS:{ if (Record.size() < 3) return error("Invalid record"); Type *FnTy = getTypeByID(Record[0]); if (!FnTy) return error("Invalid record"); Function *Fn = dyn_cast_or_null(ValueList.getConstantFwdRef(Record[1],FnTy)); if (!Fn) return error("Invalid record"); // If the function is already parsed we can insert the block address right // away. BasicBlock *BB; unsigned BBID = Record[2]; if (!BBID) // Invalid reference to entry block. return error("Invalid ID"); if (!Fn->empty()) { Function::iterator BBI = Fn->begin(), BBE = Fn->end(); for (size_t I = 0, E = BBID; I != E; ++I) { if (BBI == BBE) return error("Invalid ID"); ++BBI; } BB = &*BBI; } else { // Otherwise insert a placeholder and remember it so it can be inserted // when the function is parsed. auto &FwdBBs = BasicBlockFwdRefs[Fn]; if (FwdBBs.empty()) BasicBlockFwdRefQueue.push_back(Fn); if (FwdBBs.size() < BBID + 1) FwdBBs.resize(BBID + 1); if (!FwdBBs[BBID]) FwdBBs[BBID] = BasicBlock::Create(Context); BB = FwdBBs[BBID]; } V = BlockAddress::get(Fn, BB); break; } } ValueList.assignValue(V, NextCstNo); ++NextCstNo; } } Error BitcodeReader::parseUseLists() { if (Stream.EnterSubBlock(bitc::USELIST_BLOCK_ID)) return error("Invalid record"); // Read all the records. SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a use list record. Record.clear(); bool IsBB = false; switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: unknown type. break; case bitc::USELIST_CODE_BB: IsBB = true; LLVM_FALLTHROUGH; case bitc::USELIST_CODE_DEFAULT: { unsigned RecordLength = Record.size(); if (RecordLength < 3) // Records should have at least an ID and two indexes. return error("Invalid record"); unsigned ID = Record.back(); Record.pop_back(); Value *V; if (IsBB) { IGC_ASSERT(ID < FunctionBBs.size() && "Basic block not found"); V = FunctionBBs[ID]; } else V = ValueList[ID]; unsigned NumUses = 0; SmallDenseMap Order; for (const Use &U : V->materialized_uses()) { if (++NumUses > Record.size()) break; Order[&U] = Record[NumUses - 1]; } if (Order.size() != Record.size() || NumUses > Record.size()) // Mismatches can happen if the functions are being materialized lazily // (out-of-order), or a value has been upgraded. break; V->sortUseList([&](const Use &L, const Use &R) { return Order.lookup(&L) < Order.lookup(&R); }); break; } } } } /// When we see the block for metadata, remember where it is and then skip it. /// This lets us lazily deserialize the metadata. Error BitcodeReader::rememberAndSkipMetadata() { // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); DeferredMetadataInfo.push_back(CurBit); // Skip over the block for now. if (Stream.SkipBlock()) return error("Invalid record"); return Error::success(); } Error BitcodeReader::materializeMetadata() { for (uint64_t BitPos : DeferredMetadataInfo) { // Move the bit stream to the saved position. Stream.JumpToBit(BitPos); if (Error Err = MDLoader->parseModuleMetadata()) return Err; } // Upgrade "Linker Options" module flag to "llvm.linker.options" module-level // metadata. if (Metadata *Val = TheModule->getModuleFlag("Linker Options")) { NamedMDNode *LinkerOpts = TheModule->getOrInsertNamedMetadata("llvm.linker.options"); for (const MDOperand &MDOptions : cast(Val)->operands()) LinkerOpts->addOperand(cast(MDOptions)); } DeferredMetadataInfo.clear(); return Error::success(); } void BitcodeReader::setStripDebugInfo() { StripDebugInfo = true; } /// When we see the block for a function body, remember where it is and then /// skip it. This lets us lazily deserialize the functions. Error BitcodeReader::rememberAndSkipFunctionBody() { // Get the function we are talking about. if (FunctionsWithBodies.empty()) return error("Insufficient function protos"); Function *Fn = FunctionsWithBodies.back(); FunctionsWithBodies.pop_back(); // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); IGC_ASSERT( (DeferredFunctionInfo[Fn] == 0 || DeferredFunctionInfo[Fn] == CurBit) && "Mismatch between VST and scanned function offsets"); DeferredFunctionInfo[Fn] = CurBit; // Skip over the function block for now. if (Stream.SkipBlock()) return error("Invalid record"); return Error::success(); } Error BitcodeReader::globalCleanup() { // Patch the initializers for globals and aliases up. if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; if (!GlobalInits.empty() || !IndirectSymbolInits.empty()) return error("Malformed global initializer set"); // Look for intrinsic functions which need to be upgraded at some point for (Function &F : *TheModule) { //LLVM_UPGRADE_TODO //check this funciton upgradeDebugIntrinsics (in llvm 4.0 not present) //MDLoader->upgradeDebugIntrinsics(F); Function *NewFn; if (UpgradeIntrinsicFunction(&F, NewFn)) UpgradedIntrinsics[&F] = NewFn; else if (auto Remangled = Intrinsic::remangleIntrinsicFunction(&F)) // Some types could be renamed during loading if several modules are // loaded in the same LLVMContext (LTO scenario). In this case we should // remangle intrinsics names as well. RemangledIntrinsics[&F] = Remangled.getValue(); } // Look for global variables which need to be renamed. for (GlobalVariable &GV : TheModule->globals()) UpgradeGlobalVariable(&GV); // Force deallocation of memory for these vectors to favor the client that // want lazy deserialization. std::vector>().swap(GlobalInits); std::vector>().swap( IndirectSymbolInits); return Error::success(); } /// Support for lazy parsing of function bodies. This is required if we /// either have an old bitcode file without a VST forward declaration record, /// or if we have an anonymous function being materialized, since anonymous /// functions do not have a name and are therefore not in the VST. Error BitcodeReader::rememberAndSkipFunctionBodies() { Stream.JumpToBit(NextUnreadBit); if (Stream.AtEndOfStream()) return error("Could not find function in stream"); if (!SeenFirstFunctionBody) return error("Trying to materialize functions before seeing function blocks"); // An old bitcode file with the symbol table at the end would have // finished the parse greedily. IGC_ASSERT(SeenValueSymbolTable); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { default: return error("Expect SubBlock"); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: return error("Expect function block"); case bitc::FUNCTION_BLOCK_ID: if (Error Err = rememberAndSkipFunctionBody()) return Err; NextUnreadBit = Stream.GetCurrentBitNo(); return Error::success(); } } } } bool BitcodeReaderBase::readBlockInfo() { Optional NewBlockInfo = Stream.ReadBlockInfoBlock(); if (!NewBlockInfo) return true; BlockInfo = std::move(*NewBlockInfo); return false; } Error BitcodeReader::parseComdatRecord(ArrayRef Record) { // v1: [selection_kind, name] // v2: [strtab_offset, strtab_size, selection_kind] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.empty()) return error("Invalid record"); Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]); std::string OldFormatName; if (!UseStrtab) { if (Record.size() < 2) return error("Invalid record"); unsigned ComdatNameSize = Record[1]; OldFormatName.reserve(ComdatNameSize); for (unsigned i = 0; i != ComdatNameSize; ++i) OldFormatName += (char)Record[2 + i]; Name = OldFormatName; } Comdat *C = TheModule->getOrInsertComdat(Name); C->setSelectionKind(SK); ComdatList.push_back(C); return Error::success(); } Error BitcodeReader::parseGlobalVarRecord(ArrayRef Record) { // v1: [pointer type, isconst, initid, linkage, alignment, section, // visibility, threadlocal, unnamed_addr, externally_initialized, // dllstorageclass, comdat, attributes, preemption specifier] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.size() < 6) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); bool isConstant = Record[1] & 1; bool explicitType = Record[1] & 2; unsigned AddressSpace; if (explicitType) { AddressSpace = Record[1] >> 2; } else { if (!Ty->isPointerTy()) return error("Invalid type for value"); AddressSpace = cast(Ty)->getAddressSpace(); Ty = cast(Ty)->getElementType(); } uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); unsigned Alignment; if (Error Err = parseAlignmentValue(Record[4], Alignment)) return Err; std::string Section; if (Record[5]) { if (Record[5] - 1 >= SectionTable.size()) return error("Invalid ID"); Section = SectionTable[Record[5] - 1]; } GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; // Local linkage must have default visibility. if (Record.size() > 6 && !GlobalValue::isLocalLinkage(Linkage)) // FIXME: Change to an error if non-default in 4.0. Visibility = getDecodedVisibility(Record[6]); GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; if (Record.size() > 7) TLM = getDecodedThreadLocalMode(Record[7]); GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 8) UnnamedAddr = getDecodedUnnamedAddrType(Record[8]); bool ExternallyInitialized = false; if (Record.size() > 9) ExternallyInitialized = Record[9]; GlobalVariable *NewGV = new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, Name, nullptr, TLM, AddressSpace, ExternallyInitialized); NewGV->setAlignment(Alignment); if (!Section.empty()) NewGV->setSection(Section); NewGV->setVisibility(Visibility); NewGV->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10) NewGV->setDLLStorageClass(getDecodedDLLStorageClass(Record[10])); else upgradeDLLImportExportLinkage(NewGV, RawLinkage); ValueList.push_back(NewGV); // Remember which value to use for the global initializer. if (unsigned InitID = Record[2]) GlobalInits.push_back(std::make_pair(NewGV, InitID - 1)); if (Record.size() > 11) { if (unsigned ComdatID = Record[11]) { if (ComdatID > ComdatList.size()) return error("Invalid global variable comdat ID"); NewGV->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { NewGV->setComdat(reinterpret_cast(1)); } if (Record.size() > 12) { auto AS = getAttributes(Record[12]).getFnAttributes(); NewGV->setAttributes(AS); } if (Record.size() > 13) { NewGV->setDSOLocal(getDecodedDSOLocal(Record[13])); } return Error::success(); } Error BitcodeReader::parseFunctionRecord(ArrayRef Record) { // v1: [type, callingconv, isproto, linkage, paramattr, alignment, section, // visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat, // prefixdata, personalityfn, preemption specifier] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.size() < 8) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); if (auto *PTy = dyn_cast(Ty)) Ty = PTy->getElementType(); auto *FTy = dyn_cast(Ty); if (!FTy) return error("Invalid type for value"); auto CC = static_cast(Record[1]); if (CC & ~CallingConv::MaxID) return error("Invalid calling convention ID"); Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage, Name, TheModule); Func->setCallingConv(CC); bool isProto = Record[2]; uint64_t RawLinkage = Record[3]; Func->setLinkage(getDecodedLinkage(RawLinkage)); Func->setAttributes(getAttributes(Record[4])); unsigned Alignment; if (Error Err = parseAlignmentValue(Record[5], Alignment)) return Err; Func->setAlignment(Alignment); if (Record[6]) { if (Record[6] - 1 >= SectionTable.size()) return error("Invalid ID"); Func->setSection(SectionTable[Record[6] - 1]); } // Local linkage must have default visibility. if (!Func->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. Func->setVisibility(getDecodedVisibility(Record[7])); if (Record.size() > 8 && Record[8]) { if (Record[8] - 1 >= GCTable.size()) return error("Invalid ID"); Func->setGC(GCTable[Record[8] - 1]); } GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 9) UnnamedAddr = getDecodedUnnamedAddrType(Record[9]); Func->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10 && Record[10] != 0) FunctionPrologues.push_back(std::make_pair(Func, Record[10] - 1)); if (Record.size() > 11) Func->setDLLStorageClass(getDecodedDLLStorageClass(Record[11])); else upgradeDLLImportExportLinkage(Func, RawLinkage); if (Record.size() > 12) { if (unsigned ComdatID = Record[12]) { if (ComdatID > ComdatList.size()) return error("Invalid function comdat ID"); Func->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { Func->setComdat(reinterpret_cast(1)); } if (Record.size() > 13 && Record[13] != 0) FunctionPrefixes.push_back(std::make_pair(Func, Record[13] - 1)); if (Record.size() > 14 && Record[14] != 0) FunctionPersonalityFns.push_back(std::make_pair(Func, Record[14] - 1)); if (Record.size() > 15) { Func->setDSOLocal(getDecodedDSOLocal(Record[15])); } ValueList.push_back(Func); // If this is a function with a body, remember the prototype we are // creating now, so that we can match up the body with them later. if (!isProto) { Func->setIsMaterializable(true); FunctionsWithBodies.push_back(Func); DeferredFunctionInfo[Func] = 0; } return Error::success(); } Error BitcodeReader::parseGlobalIndirectSymbolRecord( unsigned BitCode, ArrayRef Record) { // v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST) // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, // dllstorageclass, threadlocal, unnamed_addr, // preemption specifier] (name in VST) // v1 IFUNC: [alias type, addrspace, aliasee val#, linkage, // visibility, dllstorageclass, threadlocal, unnamed_addr, // preemption specifier] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD; if (Record.size() < (3 + (unsigned)NewRecord)) return error("Invalid record"); unsigned OpNum = 0; Type *Ty = getTypeByID(Record[OpNum++]); if (!Ty) return error("Invalid record"); unsigned AddrSpace; if (!NewRecord) { auto *PTy = dyn_cast(Ty); if (!PTy) return error("Invalid type for value"); Ty = PTy->getElementType(); AddrSpace = PTy->getAddressSpace(); } else { AddrSpace = Record[OpNum++]; } auto Val = Record[OpNum++]; auto Linkage = Record[OpNum++]; GlobalIndirectSymbol *NewGA; if (BitCode == bitc::MODULE_CODE_ALIAS || BitCode == bitc::MODULE_CODE_ALIAS_OLD) NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name, TheModule); else NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name, nullptr, TheModule); // Old bitcode files didn't have visibility field. // Local linkage must have default visibility. if (OpNum != Record.size()) { auto VisInd = OpNum++; if (!NewGA->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. NewGA->setVisibility(getDecodedVisibility(Record[VisInd])); } if (OpNum != Record.size()) NewGA->setDLLStorageClass(getDecodedDLLStorageClass(Record[OpNum++])); else upgradeDLLImportExportLinkage(NewGA, Linkage); if (OpNum != Record.size()) NewGA->setThreadLocalMode(getDecodedThreadLocalMode(Record[OpNum++])); if (OpNum != Record.size()) NewGA->setUnnamedAddr(getDecodedUnnamedAddrType(Record[OpNum++])); if (OpNum != Record.size()) NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++])); ValueList.push_back(NewGA); IndirectSymbolInits.push_back(std::make_pair(NewGA, Val)); return Error::success(); } Error BitcodeReader::parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata) { if (ResumeBit) Stream.JumpToBit(ResumeBit); else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return globalCleanup(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::BLOCKINFO_BLOCK_ID: if (readBlockInfo()) return error("Malformed block"); break; case bitc::PARAMATTR_BLOCK_ID: if (Error Err = parseAttributeBlock()) return Err; break; case bitc::PARAMATTR_GROUP_BLOCK_ID: if (Error Err = parseAttributeGroupBlock()) return Err; break; case bitc::TYPE_BLOCK_ID_NEW: if (Error Err = parseTypeTable()) return Err; break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (!SeenValueSymbolTable) { // Either this is an old form VST without function index and an // associated VST forward declaration record (which would have caused // the VST to be jumped to and parsed before it was encountered // normally in the stream), or there were no function blocks to // trigger an earlier parsing of the VST. IGC_ASSERT(VSTOffset == 0 || FunctionsWithBodies.empty()); if (Error Err = parseValueSymbolTable()) return Err; SeenValueSymbolTable = true; } else { // We must have had a VST forward declaration record, which caused // the parser to jump to and parse the VST earlier. IGC_ASSERT(VSTOffset > 0); if (Stream.SkipBlock()) return error("Invalid record"); } break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; break; case bitc::METADATA_BLOCK_ID: if (ShouldLazyLoadMetadata) { if (Error Err = rememberAndSkipMetadata()) return Err; break; } IGC_ASSERT(DeferredMetadataInfo.empty() && "Unexpected deferred metadata"); if (Error Err = MDLoader->parseModuleMetadata()) return Err; break; case bitc::METADATA_KIND_BLOCK_ID: if (Error Err = MDLoader->parseMetadataKinds()) return Err; break; case bitc::FUNCTION_BLOCK_ID: // If this is the first function body we've seen, reverse the // FunctionsWithBodies list. if (!SeenFirstFunctionBody) { std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end()); if (Error Err = globalCleanup()) return Err; SeenFirstFunctionBody = true; } if (VSTOffset > 0) { // If we have a VST forward declaration record, make sure we // parse the VST now if we haven't already. It is needed to // set up the DeferredFunctionInfo vector for lazy reading. if (!SeenValueSymbolTable) { if (Error Err = BitcodeReader::parseValueSymbolTable(VSTOffset)) return Err; SeenValueSymbolTable = true; // Fall through so that we record the NextUnreadBit below. // This is necessary in case we have an anonymous function that // is later materialized. Since it will not have a VST entry we // need to fall back to the lazy parse to find its offset. } else { // If we have a VST forward declaration record, but have already // parsed the VST (just above, when the first function body was // encountered here), then we are resuming the parse after // materializing functions. The ResumeBit points to the // start of the last function block recorded in the // DeferredFunctionInfo map. Skip it. if (Stream.SkipBlock()) return error("Invalid record"); continue; } } // Support older bitcode files that did not have the function // index in the VST, nor a VST forward declaration record, as // well as anonymous functions that do not have VST entries. // Build the DeferredFunctionInfo vector on the fly. if (Error Err = rememberAndSkipFunctionBody()) return Err; // Suspend parsing when we reach the function bodies. Subsequent // materialization calls will resume it when necessary. If the bitcode // file is old, the symbol table will be at the end instead and will not // have been seen yet. In this case, just finish the parse now. if (SeenValueSymbolTable) { NextUnreadBit = Stream.GetCurrentBitNo(); // After the VST has been parsed, we need to make sure intrinsic name // are auto-upgraded. return globalCleanup(); } break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: if (Error Err = parseOperandBundleTags()) return Err; break; case bitc::SYNC_SCOPE_NAMES_BLOCK_ID: if (Error Err = parseSyncScopeNames()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { Expected VersionOrErr = parseVersionRecord(Record); if (!VersionOrErr) return VersionOrErr.takeError(); UseRelativeIDs = *VersionOrErr >= 1; break; } case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setTargetTriple(S); break; } case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); size_t index = S.find("-a64:64:64"); if (index != std::string::npos) S.replace(index, 10, ""); TheModule->setDataLayout(S); break; } case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setModuleInlineAsm(S); break; } case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N] // FIXME: Remove in 4.0. std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Ignore value. break; } case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); SectionTable.push_back(S); break; } case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); GCTable.push_back(S); break; } case bitc::MODULE_CODE_COMDAT: if (Error Err = parseComdatRecord(Record)) return Err; break; case bitc::MODULE_CODE_GLOBALVAR: if (Error Err = parseGlobalVarRecord(Record)) return Err; break; case bitc::MODULE_CODE_FUNCTION: if (Error Err = parseFunctionRecord(Record)) return Err; break; case bitc::MODULE_CODE_IFUNC: case bitc::MODULE_CODE_ALIAS: case bitc::MODULE_CODE_ALIAS_OLD: if (Error Err = parseGlobalIndirectSymbolRecord(BitCode, Record)) return Err; break; /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); TheModule->setSourceFileName(ValueName); break; } Record.clear(); } } Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata, bool IsImporting) { TheModule = M; MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting, [&](unsigned ID) { return getTypeByID(ID); }); return parseModule(0, ShouldLazyLoadMetadata); } Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) { if (!isa(PtrType)) return error("Load/Store operand is not a pointer type"); Type *ElemType = cast(PtrType)->getElementType(); if (ValType && ValType != ElemType) return error("Explicit load/store type does not match pointee " "type of pointer operand"); if (!PointerType::isLoadableOrStorableType(ElemType)) return error("Cannot load/store from pointer"); return Error::success(); } /// Lazily parse the specified function body block. Error BitcodeReader::parseFunctionBody(Function *F) { if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID)) return error("Invalid record"); // Unexpected unresolved metadata when parsing function. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: incoming forward references"); InstructionList.clear(); unsigned ModuleValueListSize = ValueList.size(); unsigned ModuleMDLoaderSize = MDLoader->size(); // Add all the function arguments to the value table. for (Argument &I : F->args()) ValueList.push_back(&I); unsigned NextValueNo = ValueList.size(); BasicBlock *CurBB = nullptr; unsigned CurBBNo = 0; DebugLoc LastLoc; auto getLastInstruction = [&]() -> Instruction * { if (CurBB && !CurBB->empty()) return &CurBB->back(); else if (CurBBNo && FunctionBBs[CurBBNo - 1] && !FunctionBBs[CurBBNo - 1]->empty()) return &FunctionBBs[CurBBNo - 1]->back(); return nullptr; }; std::vector OperandBundles; // Read all the records. SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: goto OutOfRecordLoop; case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; NextValueNo = ValueList.size(); break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (Error Err = parseValueSymbolTable()) return Err; break; case bitc::METADATA_ATTACHMENT_ID: if (Error Err = MDLoader->parseMetadataAttachment(*F, InstructionList)) return Err; break; case bitc::METADATA_BLOCK_ID: IGC_ASSERT(DeferredMetadataInfo.empty() && "Must read all module-level metadata before function-level"); if (Error Err = MDLoader->parseFunctionMetadata()) return Err; break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Instruction *I = nullptr; unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: reject return error("Invalid value"); case bitc::FUNC_CODE_DECLAREBLOCKS: { // DECLAREBLOCKS: [nblocks] if (Record.size() < 1 || Record[0] == 0) return error("Invalid record"); // Create all the basic blocks for the function. FunctionBBs.resize(Record[0]); // See if anything took the address of blocks in this function. auto BBFRI = BasicBlockFwdRefs.find(F); if (BBFRI == BasicBlockFwdRefs.end()) { for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i) FunctionBBs[i] = BasicBlock::Create(Context, "", F); } else { auto &BBRefs = BBFRI->second; // Check for invalid basic block references. if (BBRefs.size() > FunctionBBs.size()) return error("Invalid ID"); IGC_ASSERT(!BBRefs.empty() && "Unexpected empty array"); IGC_ASSERT(!BBRefs.front() && "Invalid reference to entry block"); for (unsigned I = 0, E = FunctionBBs.size(), RE = BBRefs.size(); I != E; ++I) if (I < RE && BBRefs[I]) { BBRefs[I]->insertInto(F); FunctionBBs[I] = BBRefs[I]; } else { FunctionBBs[I] = BasicBlock::Create(Context, "", F); } // Erase from the table. BasicBlockFwdRefs.erase(BBFRI); } CurBB = FunctionBBs[0]; continue; } case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN // This record indicates that the last instruction is at the same // location as the previous instruction with a location. I = getLastInstruction(); if (!I) return error("Invalid record"); I->setDebugLoc(LastLoc); I = nullptr; continue; case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia] I = getLastInstruction(); if (!I || Record.size() < 4) return error("Invalid record"); unsigned Line = Record[0], Col = Record[1]; unsigned ScopeID = Record[2], IAID = Record[3]; MDNode *Scope = nullptr, *IA = nullptr; if (ScopeID) { Scope = MDLoader->getMDNodeFwdRefOrNull(ScopeID - 1); if (!Scope) return error("Invalid record"); } if (IAID) { IA = MDLoader->getMDNodeFwdRefOrNull(IAID - 1); if (!IA) return error("Invalid record"); } LastLoc = DebugLoc::get(Line, Col, Scope, IA); I->setDebugLoc(LastLoc); I = nullptr; continue; } case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode] unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS) || OpNum+1 > Record.size()) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return error("Invalid record"); I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); InstructionList.push_back(I); if (OpNum < Record.size()) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) cast(I)->setHasNoSignedWrap(true); if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) cast(I)->setHasNoUnsignedWrap(true); } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } else if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } } break; } case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || OpNum+2 != Record.size()) return error("Invalid record"); Type *ResTy = getTypeByID(Record[OpNum]); int Opc = getDecodedCastOpcode(Record[OpNum + 1]); if (Opc == -1 || !ResTy) return error("Invalid record"); Instruction *Temp = nullptr; if ((I = UpgradeBitCastInst(Opc, Op, ResTy, Temp))) { if (Temp) { InstructionList.push_back(Temp); CurBB->getInstList().push_back(Temp); } } else { auto CastOp = (Instruction::CastOps)Opc; if (!CastInst::castIsValid(CastOp, Op, ResTy)) return error("Invalid cast"); I = CastInst::Create(CastOp, Op, ResTy); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD: case bitc::FUNC_CODE_INST_GEP_OLD: case bitc::FUNC_CODE_INST_GEP: { // GEP: type, [n x operands] unsigned OpNum = 0; Type *Ty; bool InBounds; if (BitCode == bitc::FUNC_CODE_INST_GEP) { InBounds = Record[OpNum++]; Ty = getTypeByID(Record[OpNum++]); } else { InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD; Ty = nullptr; } Value *BasePtr; if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr)) return error("Invalid record"); if (!Ty) Ty = cast(BasePtr->getType()->getScalarType()) ->getElementType(); else if (Ty != cast(BasePtr->getType()->getScalarType()) ->getElementType()) return error( "Explicit gep type does not match pointee type of pointer operand"); SmallVector GEPIdx; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); GEPIdx.push_back(Op); } I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx); InstructionList.push_back(I); if (InBounds) cast(I)->setIsInBounds(true); break; } case bitc::FUNC_CODE_INST_EXTRACTVAL: { // EXTRACTVAL: [opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("EXTRACTVAL: Invalid instruction with 0 indices"); SmallVector EXTRACTVALIdx; Type *CurTy = Agg->getType(); for (; OpNum != RecSize; ++OpNum) { bool IsArray = CurTy->isArrayTy(); bool IsStruct = CurTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("EXTRACTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= CurTy->subtypes().size()) return error("EXTRACTVAL: Invalid struct index"); if (IsArray && Index >= CurTy->getArrayNumElements()) return error("EXTRACTVAL: Invalid array index"); EXTRACTVALIdx.push_back((unsigned)Index); if (IsStruct) CurTy = CurTy->subtypes()[Index]; else CurTy = CurTy->subtypes()[0]; } I = ExtractValueInst::Create(Agg, EXTRACTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTVAL: { // INSERTVAL: [opty, opval, opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) return error("Invalid record"); Value *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Val)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("INSERTVAL: Invalid instruction with 0 indices"); SmallVector INSERTVALIdx; Type *CurTy = Agg->getType(); for (; OpNum != RecSize; ++OpNum) { bool IsArray = CurTy->isArrayTy(); bool IsStruct = CurTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("INSERTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= CurTy->subtypes().size()) return error("INSERTVAL: Invalid struct index"); if (IsArray && Index >= CurTy->getArrayNumElements()) return error("INSERTVAL: Invalid array index"); INSERTVALIdx.push_back((unsigned)Index); if (IsStruct) CurTy = CurTy->subtypes()[Index]; else CurTy = CurTy->subtypes()[0]; } if (CurTy != Val->getType()) return error("Inserted value type doesn't match aggregate type"); I = InsertValueInst::Create(Agg, Val, INSERTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval] // obsolete form of select // handles select i1 ... in old bitcode unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || popValue(Record, OpNum, NextValueNo, Type::getInt1Ty(Context), Cond)) return error("Invalid record"); I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred] // new form of select // handles select i1 or select [N x i1] unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || getValueTypePair(Record, OpNum, NextValueNo, Cond)) return error("Invalid record"); // select condition can be either i1 or [N x i1] if (VectorType* vector_type = dyn_cast(Cond->getType())) { // expect if (vector_type->getElementType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } else { // expect i1 if (Cond->getType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval] unsigned OpNum = 0; Value *Vec, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); I = ExtractElementInst::Create(Vec, Idx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval] unsigned OpNum = 0; Value *Vec, *Elt, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); if (popValue(Record, OpNum, NextValueNo, cast(Vec->getType())->getElementType(), Elt) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); I = InsertElementInst::Create(Vec, Elt, Idx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval] unsigned OpNum = 0; Value *Vec1, *Vec2, *Mask; if (getValueTypePair(Record, OpNum, NextValueNo, Vec1) || popValue(Record, OpNum, NextValueNo, Vec1->getType(), Vec2)) return error("Invalid record"); if (getValueTypePair(Record, OpNum, NextValueNo, Mask)) return error("Invalid record"); if (!Vec1->getType()->isVectorTy() || !Vec2->getType()->isVectorTy()) return error("Invalid type for value"); I = new ShuffleVectorInst(Vec1, Vec2, Mask); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred] // Old form of ICmp/FCmp returning bool // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were // both legal on vectors but had different behaviour. case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred] // FCmp/ICmp returning bool or vector of bool unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS)) return error("Invalid record"); unsigned PredVal = Record[OpNum]; bool IsFP = LHS->getType()->isFPOrFPVectorTy(); FastMathFlags FMF; if (IsFP && Record.size() > OpNum+1) FMF = getDecodedFastMathFlags(Record[++OpNum]); if (OpNum+1 != Record.size()) return error("Invalid record"); if (LHS->getType()->isFPOrFPVectorTy()) I = new FCmpInst((FCmpInst::Predicate)PredVal, LHS, RHS); else I = new ICmpInst((ICmpInst::Predicate)PredVal, LHS, RHS); if (FMF.any()) I->setFastMathFlags(FMF); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval] { unsigned Size = Record.size(); if (Size == 0) { I = ReturnInst::Create(Context); InstructionList.push_back(I); break; } unsigned OpNum = 0; Value *Op = nullptr; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); if (OpNum != Record.size()) return error("Invalid record"); I = ReturnInst::Create(Context, Op); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#] if (Record.size() != 1 && Record.size() != 3) return error("Invalid record"); BasicBlock *TrueDest = getBasicBlock(Record[0]); if (!TrueDest) return error("Invalid record"); if (Record.size() == 1) { I = BranchInst::Create(TrueDest); InstructionList.push_back(I); } else { BasicBlock *FalseDest = getBasicBlock(Record[1]); Value *Cond = getValue(Record, 2, NextValueNo, Type::getInt1Ty(Context)); if (!FalseDest || !Cond) return error("Invalid record"); I = BranchInst::Create(TrueDest, FalseDest, Cond); InstructionList.push_back(I); } break; } case bitc::FUNC_CODE_INST_CLEANUPRET: { // CLEANUPRET: [val] or [val,bb#] if (Record.size() != 1 && Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CleanupPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CleanupPad) return error("Invalid record"); BasicBlock *UnwindDest = nullptr; if (Record.size() == 2) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } I = CleanupReturnInst::Create(CleanupPad, UnwindDest); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHRET: { // CATCHRET: [val,bb#] if (Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CatchPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CatchPad) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); I = CatchReturnInst::Create(CatchPad, BB); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHSWITCH: { // CATCHSWITCH: [tok,num,(bb)*,bb?] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumHandlers = Record[Idx++]; SmallVector Handlers; for (unsigned Op = 0; Op != NumHandlers; ++Op) { BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); Handlers.push_back(BB); } BasicBlock *UnwindDest = nullptr; if (Idx + 1 == Record.size()) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } if (Record.size() != Idx) return error("Invalid record"); auto *CatchSwitch = CatchSwitchInst::Create(ParentPad, UnwindDest, NumHandlers); for (BasicBlock *Handler : Handlers) CatchSwitch->addHandler(Handler); I = CatchSwitch; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHPAD: case bitc::FUNC_CODE_INST_CLEANUPPAD: { // [tok,num,(ty,val)*] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumArgOperands = Record[Idx++]; SmallVector Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); Args.push_back(Val); } if (Record.size() != Idx) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_CLEANUPPAD) I = CleanupPadInst::Create(ParentPad, Args); else I = CatchPadInst::Create(ParentPad, Args); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...] // Check magic if ((Record[0] >> 16) == SWITCH_INST_MAGIC) { // "New" SwitchInst format with case ranges. The changes to write this // format were reverted but we still recognize bitcode that uses it. // Hopefully someday we will have support for case ranges and can use // this format again. Type *OpTy = getTypeByID(Record[1]); unsigned ValueBitWidth = cast(OpTy)->getBitWidth(); Value *Cond = getValue(Record, 2, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[3]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = Record[4]; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); unsigned CurIdx = 5; for (unsigned i = 0; i != NumCases; ++i) { SmallVector CaseVals; unsigned NumItems = Record[CurIdx++]; for (unsigned ci = 0; ci != NumItems; ++ci) { bool isSingleNumber = Record[CurIdx++]; APInt Low; unsigned ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; Low = readWideAPInt(makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; if (!isSingleNumber) { ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; APInt High = readWideAPInt( makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; // FIXME: It is not clear whether values in the range should be // compared as signed or unsigned values. The partially // implemented changes that used this format in the past used // unsigned comparisons. for ( ; Low.ule(High); ++Low) CaseVals.push_back(ConstantInt::get(Context, Low)); } else CaseVals.push_back(ConstantInt::get(Context, Low)); } BasicBlock *DestBB = getBasicBlock(Record[CurIdx++]); for (SmallVector::iterator cvi = CaseVals.begin(), cve = CaseVals.end(); cvi != cve; ++cvi) SI->addCase(*cvi, DestBB); } I = SI; break; } // Old SwitchInst format without case ranges. if (Record.size() < 3 || (Record.size() & 1) == 0) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Cond = getValue(Record, 1, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[2]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = (Record.size()-3)/2; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); for (unsigned i = 0, e = NumCases; i != e; ++i) { ConstantInt *CaseVal = dyn_cast_or_null(getFnValueByID(Record[3+i*2], OpTy)); BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]); if (!CaseVal || !DestBB) { delete SI; return error("Invalid record"); } SI->addCase(CaseVal, DestBB); } I = SI; break; } case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...] if (Record.size() < 2) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Address = getValue(Record, 1, NextValueNo, OpTy); if (!OpTy || !Address) return error("Invalid record"); unsigned NumDests = Record.size()-2; IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests); InstructionList.push_back(IBI); for (unsigned i = 0, e = NumDests; i != e; ++i) { if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) { IBI->addDestination(DestBB); } else { delete IBI; return error("Invalid record"); } } I = IBI; break; } case bitc::FUNC_CODE_INST_INVOKE: { // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...] if (Record.size() < 4) return error("Invalid record"); unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; BasicBlock *NormalBB = getBasicBlock(Record[OpNum++]); BasicBlock *UnwindBB = getBasicBlock(Record[OpNum++]); FunctionType *FTy = nullptr; if (CCInfo >> 13 & 1 && !(FTy = dyn_cast(getTypeByID(Record[OpNum++])))) return error("Explicit invoke type is not a function type"); Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) return error("Invalid record"); PointerType *CalleeTy = dyn_cast(Callee->getType()); if (!CalleeTy) return error("Callee is not a pointer"); if (!FTy) { FTy = dyn_cast(CalleeTy->getElementType()); if (!FTy) return error("Callee is not of pointer to function type"); } else if (CalleeTy->getElementType() != FTy) return error("Explicit invoke type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Ops; for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { Ops.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); if (!Ops.back()) return error("Invalid record"); } if (!FTy->isVarArg()) { if (Record.size() != OpNum) return error("Invalid record"); } else { // Read type/value pairs for varargs params. while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Ops.push_back(Op); } } I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops, OperandBundles); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast(CallingConv::MaxID & CCInfo)); cast(I)->setAttributes(PAL); break; } case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval] unsigned Idx = 0; Value *Val = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); I = ResumeInst::Create(Val); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE I = new UnreachableInst(Context); InstructionList.push_back(I); break; case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] if (Record.size() < 1 || ((Record.size()-1)&1)) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2); InstructionList.push_back(PN); for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) { Value *V; // With the new function encoding, it is possible that operands have // negative IDs (for forward references). Use a signed VBR // representation to keep the encoding small. if (UseRelativeIDs) V = getValueSigned(Record, 1+i, NextValueNo, Ty); else V = getValue(Record, 1+i, NextValueNo, Ty); BasicBlock *BB = getBasicBlock(Record[2+i]); if (!V || !BB) return error("Invalid record"); PN->addIncoming(V, BB); } I = PN; break; } case bitc::FUNC_CODE_INST_LANDINGPAD: case bitc::FUNC_CODE_INST_LANDINGPAD_OLD: { // LANDINGPAD: [ty, val, val, num, (id0,val0 ...)?] unsigned Idx = 0; if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD) { if (Record.size() < 3) return error("Invalid record"); } else { IGC_ASSERT(BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD); if (Record.size() < 4) return error("Invalid record"); } Type *Ty = getTypeByID(Record[Idx++]); if (!Ty) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD) { Value *PersFn = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, PersFn)) return error("Invalid record"); if (!F->hasPersonalityFn()) F->setPersonalityFn(cast(PersFn)); else if (F->getPersonalityFn() != cast(PersFn)) return error("Personality function mismatch"); } bool IsCleanup = !!Record[Idx++]; unsigned NumClauses = Record[Idx++]; LandingPadInst *LP = LandingPadInst::Create(Ty, NumClauses); LP->setCleanup(IsCleanup); for (unsigned J = 0; J != NumClauses; ++J) { LandingPadInst::ClauseType CT = LandingPadInst::ClauseType(Record[Idx++]); (void)CT; Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) { delete LP; return error("Invalid record"); } IGC_ASSERT((CT != LandingPadInst::Catch || !isa(Val->getType())) && "Catch clause has a invalid type!"); IGC_ASSERT((CT != LandingPadInst::Filter || isa(Val->getType())) && "Filter clause has invalid type!"); LP->addClause(cast(Val)); } I = LP; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align] if (Record.size() != 4) return error("Invalid record"); uint64_t AlignRecord = Record[3]; const uint64_t InAllocaMask = uint64_t(1) << 5; const uint64_t ExplicitTypeMask = uint64_t(1) << 6; const uint64_t SwiftErrorMask = uint64_t(1) << 7; const uint64_t FlagMask = InAllocaMask | ExplicitTypeMask | SwiftErrorMask; bool InAlloca = AlignRecord & InAllocaMask; bool SwiftError = AlignRecord & SwiftErrorMask; Type *Ty = getTypeByID(Record[0]); if ((AlignRecord & ExplicitTypeMask) == 0) { auto *PTy = dyn_cast_or_null(Ty); if (!PTy) return error("Old-style alloca with a non-pointer type"); Ty = PTy->getElementType(); } Type *OpTy = getTypeByID(Record[1]); Value *Size = getFnValueByID(Record[2], OpTy); unsigned Align; if (Error Err = parseAlignmentValue(AlignRecord & ~FlagMask, Align)) { return Err; } if (!Ty || !Size) return error("Invalid record"); // FIXME: Make this an optional field. const DataLayout &DL = TheModule->getDataLayout(); unsigned AS = DL.getAllocaAddrSpace(); AllocaInst *AI = new AllocaInst(Ty, AS, Size, Align); AI->setUsedWithInAlloca(InAlloca); AI->setSwiftError(SwiftError); I = AI; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || (OpNum + 2 != Record.size() && OpNum + 3 != Record.size())) return error("Invalid record"); Type *Ty = nullptr; if (OpNum + 3 == Record.size()) Ty = getTypeByID(Record[OpNum++]); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; if (!Ty) Ty = cast(Op->getType())->getElementType(); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Ty, Op, "", Record[OpNum + 1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOADATOMIC: { // LOADATOMIC: [opty, op, align, vol, ordering, ssid] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || (OpNum + 4 != Record.size() && OpNum + 5 != Record.size())) return error("Invalid record"); Type *Ty = nullptr; if (OpNum + 5 == Record.size()) Ty = getTypeByID(Record[OpNum++]); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; if (!Ty) Ty = cast(Op->getType())->getElementType(); AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Release || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Op, "", Record[OpNum+1], Align, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STORE: case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol] unsigned OpNum = 0; Value *Val, *Ptr; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || (BitCode == bitc::FUNC_CODE_INST_STORE ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val)) || OpNum + 2 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum+1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STOREATOMIC: case bitc::FUNC_CODE_INST_STOREATOMIC_OLD: { // STOREATOMIC: [ptrty, ptr, val, align, vol, ordering, ssid] unsigned OpNum = 0; Value *Val, *Ptr; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || !isa(Ptr->getType()) || (BitCode == bitc::FUNC_CODE_INST_STOREATOMIC ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val)) || OpNum + 4 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Acquire || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum+1], Align, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMPXCHG_OLD: case bitc::FUNC_CODE_INST_CMPXCHG: { // CMPXCHG:[ptrty, ptr, cmp, new, vol, successordering, ssid, // failureordering?, isweak?] unsigned OpNum = 0; Value *Ptr, *Cmp, *New; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || (BitCode == bitc::FUNC_CODE_INST_CMPXCHG ? getValueTypePair(Record, OpNum, NextValueNo, Cmp) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Cmp)) || popValue(Record, OpNum, NextValueNo, Cmp->getType(), New) || Record.size() < OpNum + 3 || Record.size() > OpNum + 5) return error("Invalid record"); AtomicOrdering SuccessOrdering = getDecodedOrdering(Record[OpNum + 1]); if (SuccessOrdering == AtomicOrdering::NotAtomic || SuccessOrdering == AtomicOrdering::Unordered) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 2]); if (Error Err = typeCheckLoadStoreInst(Cmp->getType(), Ptr->getType())) return Err; AtomicOrdering FailureOrdering; if (Record.size() < 7) FailureOrdering = AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrdering); else FailureOrdering = getDecodedOrdering(Record[OpNum + 3]); I = new AtomicCmpXchgInst(Ptr, Cmp, New, SuccessOrdering, FailureOrdering, SSID); cast(I)->setVolatile(Record[OpNum]); if (Record.size() < 8) { // Before weak cmpxchgs existed, the instruction simply returned the // value loaded from memory, so bitcode files from that era will be // expecting the first component of a modern cmpxchg. CurBB->getInstList().push_back(I); I = ExtractValueInst::Create(I, 0); } else { cast(I)->setWeak(Record[OpNum+4]); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ATOMICRMW: { // ATOMICRMW:[ptrty, ptr, val, op, vol, ordering, ssid] unsigned OpNum = 0; Value *Ptr, *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || !isa(Ptr->getType()) || popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val) || OpNum+4 != Record.size()) return error("Invalid record"); AtomicRMWInst::BinOp Operation = getDecodedRMWOperation(Record[OpNum]); if (Operation < AtomicRMWInst::FIRST_BINOP || Operation > AtomicRMWInst::LAST_BINOP) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); I = new AtomicRMWInst(Operation, Ptr, Val, Ordering, SSID); cast(I)->setVolatile(Record[OpNum+1]); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_FENCE: { // FENCE:[ordering, ssid] if (2 != Record.size()) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[0]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered || Ordering == AtomicOrdering::Monotonic) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[1]); I = new FenceInst(Context, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CALL: { // CALL: [paramattrs, cc, fmf, fnty, fnid, arg0, arg1...] if (Record.size() < 3) return error("Invalid record"); unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; FastMathFlags FMF; if ((CCInfo >> bitc::CALL_FMF) & 1) { FMF = getDecodedFastMathFlags(Record[OpNum++]); if (!FMF.any()) return error("Fast math flags indicator set for call with no FMF"); } FunctionType *FTy = nullptr; if (CCInfo >> bitc::CALL_EXPLICIT_TYPE & 1 && !(FTy = dyn_cast(getTypeByID(Record[OpNum++])))) return error("Explicit call type is not a function type"); Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) return error("Invalid record"); PointerType *OpTy = dyn_cast(Callee->getType()); if (!OpTy) return error("Callee is not a pointer type"); if (!FTy) { FTy = dyn_cast(OpTy->getElementType()); if (!FTy) return error("Callee is not of pointer to function type"); } else if (OpTy->getElementType() != FTy) return error("Explicit call type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Args; // Read the fixed params. for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { if (FTy->getParamType(i)->isLabelTy()) Args.push_back(getBasicBlock(Record[OpNum])); else Args.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); if (!Args.back()) return error("Invalid record"); } // Read type/value pairs for varargs params. if (!FTy->isVarArg()) { if (OpNum != Record.size()) return error("Invalid record"); } else { while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Args.push_back(Op); } } I = CallInst::Create(FTy, Callee, Args, OperandBundles); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast((0x7ff & CCInfo) >> bitc::CALL_CCONV)); CallInst::TailCallKind TCK = CallInst::TCK_None; if (CCInfo & 1 << bitc::CALL_TAIL) TCK = CallInst::TCK_Tail; if (CCInfo & (1 << bitc::CALL_MUSTTAIL)) TCK = CallInst::TCK_MustTail; if (CCInfo & (1 << bitc::CALL_NOTAIL)) TCK = CallInst::TCK_NoTail; cast(I)->setTailCallKind(TCK); cast(I)->setAttributes(PAL); if (FMF.any()) { if (!isa(I)) return error("Fast-math-flags specified for call without " "floating-point scalar or vector return type"); I->setFastMathFlags(FMF); } break; } case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty] if (Record.size() < 3) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Op = getValue(Record, 1, NextValueNo, OpTy); Type *ResTy = getTypeByID(Record[2]); if (!OpTy || !Op || !ResTy) return error("Invalid record"); I = new VAArgInst(Op, ResTy); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_OPERAND_BUNDLE: { // A call or an invoke can be optionally prefixed with some variable // number of operand bundle blocks. These blocks are read into // OperandBundles and consumed at the next call or invoke instruction. if (Record.size() < 1 || Record[0] >= BundleTags.size()) return error("Invalid record"); std::vector Inputs; unsigned OpNum = 1; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Inputs.push_back(Op); } OperandBundles.emplace_back(BundleTags[Record[0]], std::move(Inputs)); continue; } } // Add instruction to end of current BB. If there is no current BB, reject // this file. if (!CurBB) { I->deleteValue(); return error("Invalid instruction with no BB"); } if (!OperandBundles.empty()) { I->deleteValue(); return error("Operand bundles found with no consumer"); } CurBB->getInstList().push_back(I); // If this was a terminator instruction, move to the next block. if (isa(I)) { ++CurBBNo; CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr; } // Non-void values get registered in the value table for future use. if (I && !I->getType()->isVoidTy()) ValueList.assignValue(I, NextValueNo++); } OutOfRecordLoop: if (!OperandBundles.empty()) return error("Operand bundles found with no consumer"); // Check the function list for unresolved values. if (Argument *A = dyn_cast(ValueList.back())) { if (!A->getParent()) { // We found at least one unresolved value. Nuke them all to avoid leaks. for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){ if ((A = dyn_cast_or_null(ValueList[i])) && !A->getParent()) { A->replaceAllUsesWith(UndefValue::get(A->getType())); delete A; } } return error("Never resolved value found in function"); } } // Unexpected unresolved metadata about to be dropped. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: outgoing forward refs"); // Trim the value list down to the size it was before we parsed this function. ValueList.shrinkTo(ModuleValueListSize); MDLoader->shrinkTo(ModuleMDLoaderSize); std::vector().swap(FunctionBBs); return Error::success(); } /// Find the function body in the bitcode stream Error BitcodeReader::findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator) { while (DeferredFunctionInfoIterator->second == 0) { // This is the fallback handling for the old format bitcode that // didn't contain the function index in the VST, or when we have // an anonymous function which would not have a VST entry. // Assert that we have one of those two cases. IGC_ASSERT(VSTOffset == 0 || !F->hasName()); // Parse the next body in the stream and set its position in the // DeferredFunctionInfo map. if (Error Err = rememberAndSkipFunctionBodies()) return Err; } return Error::success(); } SyncScope::ID BitcodeReader::getDecodedSyncScopeID(unsigned Val) { if (Val == SyncScope::SingleThread || Val == SyncScope::System) return SyncScope::ID(Val); if (Val >= SSIDs.size()) return SyncScope::System; // Map unknown synchronization scopes to system. return SSIDs[Val]; } //===----------------------------------------------------------------------===// // GVMaterializer implementation //===----------------------------------------------------------------------===// Error BitcodeReader::materialize(GlobalValue *GV) { Function *F = dyn_cast(GV); // If it's not a function or is already material, ignore the request. if (!F || !F->isMaterializable()) return Error::success(); DenseMap::iterator DFII = DeferredFunctionInfo.find(F); IGC_ASSERT(DFII != DeferredFunctionInfo.end() && "Deferred function not found!"); // If its position is recorded as 0, its body is somewhere in the stream // but we haven't seen it yet. if (DFII->second == 0) if (Error Err = findFunctionInStream(F, DFII)) return Err; // Materialize metadata before parsing any function bodies. if (Error Err = materializeMetadata()) return Err; // Move the bit stream to the saved position of the deferred function body. Stream.JumpToBit(DFII->second); if (Error Err = parseFunctionBody(F)) return Err; F->setIsMaterializable(false); if (StripDebugInfo) stripDebugInfo(*F); // Upgrade any old intrinsic calls in the function. for (auto &I : UpgradedIntrinsics) { for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) { User *U = *UI; ++UI; if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } } // Update calls to the remangled intrinsics for (auto &I : RemangledIntrinsics) for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) // Don't expect any other users than call sites CallSite(*UI++).setCalledFunction(I.second); // Finish fn->subprogram upgrade for materialized functions. if (DISubprogram *SP = MDLoader->lookupSubprogramForFunction(F)) F->setSubprogram(SP); // Check if the TBAA Metadata are valid, otherwise we will need to strip them. if (!MDLoader->isStrippingTBAA()) { for (auto &I : instructions(F)) { MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa); if (!TBAA || TBAAVerifyHelper.visitTBAAMetadata(I, TBAA)) continue; MDLoader->setStripTBAA(true); stripTBAA(F->getParent()); } } // Bring in any functions that this function forward-referenced via // blockaddresses. return materializeForwardReferencedFunctions(); } Error BitcodeReader::materializeModule() { if (Error Err = materializeMetadata()) return Err; // Promise to materialize all forward references. WillMaterializeAllForwardRefs = true; // Iterate over the module, deserializing any functions that are still on // disk. for (Function &F : *TheModule) { if (Error Err = materialize(&F)) return Err; } // At this point, if there are any function bodies, parse the rest of // the bits in the module past the last function block we have recorded // through either lazy scanning or the VST. if (LastFunctionBlockBit || NextUnreadBit) if (Error Err = parseModule(LastFunctionBlockBit > NextUnreadBit ? LastFunctionBlockBit : NextUnreadBit)) return Err; // Check that all block address forward references got resolved (as we // promised above). if (!BasicBlockFwdRefs.empty()) return error("Never resolved function from blockaddress"); // Upgrade any intrinsic calls that slipped through (should not happen!) and // delete the old functions to clean up. We can't do this unless the entire // module is materialized because there could always be another function body // with calls to the old function. for (auto &I : UpgradedIntrinsics) { for (auto *U : I.first->users()) { if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } if (!I.first->use_empty()) I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } UpgradedIntrinsics.clear(); // Do the same for remangled intrinsics for (auto &I : RemangledIntrinsics) { I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } RemangledIntrinsics.clear(); UpgradeDebugInfo(*TheModule); UpgradeModuleFlags(*TheModule); return Error::success(); } std::vector BitcodeReader::getIdentifiedStructTypes() const { return IdentifiedStructTypes; } ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader( BitstreamCursor Cursor, StringRef Strtab, ModuleSummaryIndex &TheIndex, StringRef ModulePath, unsigned ModuleId) : BitcodeReaderBase(std::move(Cursor), Strtab), TheIndex(TheIndex), ModulePath(ModulePath), ModuleId(ModuleId) {} ModuleSummaryIndex::ModuleInfo * ModuleSummaryIndexBitcodeReader::addThisModule() { return TheIndex.addModule(ModulePath, ModuleId); } std::pair ModuleSummaryIndexBitcodeReader::getValueInfoFromValueId(unsigned ValueId) { auto VGI = ValueIdToValueInfoMap[ValueId]; IGC_ASSERT(VGI.first); return VGI; } void ModuleSummaryIndexBitcodeReader::setValueGUID( uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage, StringRef SourceFileName) { std::string GlobalId = GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName); auto ValueGUID = GlobalValue::getGUID(GlobalId); auto OriginalNameID = ValueGUID; if (GlobalValue::isLocalLinkage(Linkage)) OriginalNameID = GlobalValue::getGUID(ValueName); ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(ValueGUID), OriginalNameID); } // Specialized value symbol table parser used when reading module index // blocks where we don't actually create global values. The parsed information // is saved in the bitcode reader for use when later parsing summaries. Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap) { // With a strtab the VST is not required to parse the summary. if (UseStrtab) return Error::success(); IGC_ASSERT(Offset > 0 && "Expected non-zero VST offset"); uint64_t CurrentBit = jumpToValueSymbolTable(Offset, Stream); if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this value table. SmallString<128> ValueName; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // Done parsing VST, jump back to wherever we came from. Stream.JumpToBit(CurrentBit); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore (e.g. VST_CODE_BBENTRY records). break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] if (convertToString(Record, 1, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; setValueGUID(ValueID, ValueName, Linkage, SourceFileName); ValueName.clear(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] if (convertToString(Record, 2, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; setValueGUID(ValueID, ValueName, Linkage, SourceFileName); ValueName.clear(); break; } case bitc::VST_CODE_COMBINED_ENTRY: { // VST_CODE_COMBINED_ENTRY: [valueid, refguid] unsigned ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; // The "original name", which is the second value of the pair will be // overriden later by a FS_COMBINED_ORIGINAL_NAME in the combined index. ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(RefGUID), RefGUID); break; } } } } // Parse just the blocks needed for building the index out of the module. // At the end of this routine the module Index is populated with a map // from global value id to GlobalValueSummary objects. Error ModuleSummaryIndexBitcodeReader::parseModule() { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; DenseMap ValueIdToLinkageMap; unsigned ValueId = 0; // Read the index for this module. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::BLOCKINFO_BLOCK_ID: // Need to parse these to get abbrev ids (e.g. for VST) if (readBlockInfo()) return error("Malformed block"); break; case bitc::VALUE_SYMTAB_BLOCK_ID: // Should have been parsed earlier via VSTOffset, unless there // is no summary section. IGC_ASSERT(((SeenValueSymbolTable && VSTOffset > 0) || !SeenGlobalValSummary) && "Expected early VST parse via VSTOffset record"); if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID: IGC_ASSERT(!SeenValueSymbolTable && "Already read VST when parsing summary block?"); // We might not have a VST if there were no values in the // summary. An empty summary block generated when we are // performing ThinLTO compiles so we don't later invoke // the regular LTO process on them. if (VSTOffset > 0) { if (Error Err = parseValueSymbolTable(VSTOffset, ValueIdToLinkageMap)) return Err; SeenValueSymbolTable = true; } SeenGlobalValSummary = true; if (Error Err = parseEntireSummary(Entry.ID)) return Err; break; case bitc::MODULE_STRTAB_BLOCK_ID: if (Error Err = parseModuleStringTable()) return Err; break; } continue; case BitstreamEntry::Record: { Record.clear(); auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { if (Error Err = parseVersionRecord(Record).takeError()) return Err; break; } /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: { SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); SourceFileName = ValueName.c_str(); break; } /// MODULE_CODE_HASH: [5*i32] case bitc::MODULE_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); auto &Hash = addThisModule()->second.second; int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); Hash[Pos++] = Val; } break; } /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one // word before the start of the identification or module block, which // was historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; // v1 GLOBALVAR: [pointer type, isconst, initid, linkage, ...] // v1 FUNCTION: [type, callingconv, isproto, linkage, ...] // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, ...] // v2: [strtab offset, strtab size, v1] case bitc::MODULE_CODE_GLOBALVAR: case bitc::MODULE_CODE_FUNCTION: case bitc::MODULE_CODE_ALIAS: { StringRef Name; ArrayRef GVRecord; std::tie(Name, GVRecord) = readNameFromStrtab(Record); if (GVRecord.size() <= 3) return error("Invalid record"); uint64_t RawLinkage = GVRecord[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); if (!UseStrtab) { ValueIdToLinkageMap[ValueId++] = Linkage; break; } setValueGUID(ValueId++, Name, Linkage, SourceFileName); break; } } } continue; } } } std::vector ModuleSummaryIndexBitcodeReader::makeRefList(ArrayRef Record) { std::vector Ret; Ret.reserve(Record.size()); for (uint64_t RefValueId : Record) Ret.push_back(getValueInfoFromValueId(RefValueId).first); return Ret; } std::vector ModuleSummaryIndexBitcodeReader::makeCallList( ArrayRef Record, bool IsOldProfileFormat, bool HasProfile) { std::vector Ret; Ret.reserve(Record.size()); for (unsigned I = 0, E = Record.size(); I != E; ++I) { CalleeInfo::HotnessType Hotness = CalleeInfo::HotnessType::Unknown; ValueInfo Callee = getValueInfoFromValueId(Record[I]).first; if (IsOldProfileFormat) { I += 1; // Skip old callsitecount field if (HasProfile) I += 1; // Skip old profilecount field } else if (HasProfile) Hotness = static_cast(Record[++I]); Ret.push_back(FunctionSummary::EdgeTy{Callee, CalleeInfo{Hotness, 0}}); } return Ret; } // Eagerly parse the entire summary block. This populates the GlobalValueSummary // objects in the index. Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { if (Stream.EnterSubBlock(ID)) return error("Invalid record"); SmallVector Record; // Parse version { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); if (Entry.Kind != BitstreamEntry::Record) return error("Invalid Summary Block: record for version expected"); if (Stream.readRecord(Entry.ID, Record) != bitc::FS_VERSION) return error("Invalid Summary Block: version expected"); } const uint64_t Version = Record[0]; const bool IsOldProfileFormat = Version == 1; if (Version < 1 || Version > 4) return error("Invalid summary version " + Twine(Version) + ", 1, 2, 3 or 4 expected"); Record.clear(); // Keep around the last seen summary to be used when we see an optional // "OriginalName" attachement. GlobalValueSummary *LastSeenSummary = nullptr; GlobalValue::GUID LastSeenGUID = 0; // We can expect to see any number of type ID information records before // each function summary records; these variables store the information // collected so far so that it can be used to create the summary object. std::vector PendingTypeTests; std::vector PendingTypeTestAssumeVCalls, PendingTypeCheckedLoadVCalls; std::vector PendingTypeTestAssumeConstVCalls, PendingTypeCheckedLoadConstVCalls; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. The record format depends on whether this // is a per-module index or a combined index file. In the per-module // case the records contain the associated value's ID for correlation // with VST entries. In the combined index the correlation is done // via the bitcode offset of the summary records (which were saved // in the combined index VST entries). The records also contain // information used for ThinLTO renaming and importing. Record.clear(); auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: ignore. break; case bitc::FS_VALUE_GUID: { // [valueid, refguid] uint64_t ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(RefGUID), RefGUID); break; } // FS_PERMODULE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_PERMODULE_PROFILE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, // n x (valueid, hotness)] case bitc::FS_PERMODULE: case bitc::FS_PERMODULE_PROFILE: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned InstCount = Record[2]; uint64_t RawFunFlags = 0; unsigned NumRefs = Record[3]; int RefListStartIndex = 4; if (Version >= 4) { RawFunFlags = Record[3]; NumRefs = Record[4]; RefListStartIndex = 5; } auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_PERMODULE_PROFILE); std::vector Calls = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile); auto FS = llvm::make_unique( Flags, InstCount, getDecodedFFlags(RawFunFlags), std::move(Refs), std::move(Calls), std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeCheckedLoadConstVCalls)); PendingTypeTests.clear(); PendingTypeTestAssumeVCalls.clear(); PendingTypeCheckedLoadVCalls.clear(); PendingTypeTestAssumeConstVCalls.clear(); PendingTypeCheckedLoadConstVCalls.clear(); auto VIAndOriginalGUID = getValueInfoFromValueId(ValueID); FS->setModulePath(addThisModule()->first()); FS->setOriginalName(VIAndOriginalGUID.second); TheIndex.addGlobalValueSummary(VIAndOriginalGUID.first, std::move(FS)); break; } // FS_ALIAS: [valueid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_PERMODULE entries, as // they expect all aliasee summaries to be available. case bitc::FS_ALIAS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned AliaseeID = Record[2]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = llvm::make_unique(Flags); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. AS->setModulePath(addThisModule()->first()); GlobalValue::GUID AliaseeGUID = getValueInfoFromValueId(AliaseeID).first.getGUID(); auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeGUID, ModulePath); if (!AliaseeInModule) return error("Alias expects aliasee summary to be parsed"); AS->setAliasee(AliaseeInModule); AS->setAliaseeGUID(AliaseeGUID); auto GUID = getValueInfoFromValueId(ValueID); AS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(AS)); break; } // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, n x valueid] case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); std::vector Refs = makeRefList(ArrayRef(Record).slice(2)); auto FS = llvm::make_unique(Flags, std::move(Refs)); FS->setModulePath(addThisModule()->first()); auto GUID = getValueInfoFromValueId(ValueID); FS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(FS)); break; } // FS_COMBINED: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid, hotness)] case bitc::FS_COMBINED: case bitc::FS_COMBINED_PROFILE: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned InstCount = Record[3]; uint64_t RawFunFlags = 0; unsigned NumRefs = Record[4]; int RefListStartIndex = 5; if (Version >= 4) { RawFunFlags = Record[4]; NumRefs = Record[5]; RefListStartIndex = 6; } auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_COMBINED_PROFILE); std::vector Edges = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile); ValueInfo VI = getValueInfoFromValueId(ValueID).first; auto FS = llvm::make_unique( Flags, InstCount, getDecodedFFlags(RawFunFlags), std::move(Refs), std::move(Edges), std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeCheckedLoadConstVCalls)); PendingTypeTests.clear(); PendingTypeTestAssumeVCalls.clear(); PendingTypeCheckedLoadVCalls.clear(); PendingTypeTestAssumeConstVCalls.clear(); PendingTypeCheckedLoadConstVCalls.clear(); LastSeenSummary = FS.get(); LastSeenGUID = VI.getGUID(); FS->setModulePath(ModuleIdMap[ModuleId]); TheIndex.addGlobalValueSummary(VI, std::move(FS)); break; } // FS_COMBINED_ALIAS: [valueid, modid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_COMBINED entries, as // they expect all aliasee summaries to be available. case bitc::FS_COMBINED_ALIAS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned AliaseeValueId = Record[3]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = llvm::make_unique(Flags); LastSeenSummary = AS.get(); AS->setModulePath(ModuleIdMap[ModuleId]); auto AliaseeGUID = getValueInfoFromValueId(AliaseeValueId).first.getGUID(); auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeGUID, AS->modulePath()); AS->setAliasee(AliaseeInModule); AS->setAliaseeGUID(AliaseeGUID); ValueInfo VI = getValueInfoFromValueId(ValueID).first; LastSeenGUID = VI.getGUID(); TheIndex.addGlobalValueSummary(VI, std::move(AS)); break; } // FS_COMBINED_GLOBALVAR_INIT_REFS: [valueid, modid, flags, n x valueid] case bitc::FS_COMBINED_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); std::vector Refs = makeRefList(ArrayRef(Record).slice(3)); auto FS = llvm::make_unique(Flags, std::move(Refs)); LastSeenSummary = FS.get(); FS->setModulePath(ModuleIdMap[ModuleId]); ValueInfo VI = getValueInfoFromValueId(ValueID).first; LastSeenGUID = VI.getGUID(); TheIndex.addGlobalValueSummary(VI, std::move(FS)); break; } // FS_COMBINED_ORIGINAL_NAME: [original_name] case bitc::FS_COMBINED_ORIGINAL_NAME: { uint64_t OriginalName = Record[0]; if (!LastSeenSummary) return error("Name attachment that does not follow a combined record"); LastSeenSummary->setOriginalName(OriginalName); TheIndex.addOriginalName(LastSeenGUID, OriginalName); // Reset the LastSeenSummary LastSeenSummary = nullptr; LastSeenGUID = 0; break; } case bitc::FS_TYPE_TESTS: IGC_ASSERT(PendingTypeTests.empty()); PendingTypeTests.insert(PendingTypeTests.end(), Record.begin(), Record.end()); break; case bitc::FS_TYPE_TEST_ASSUME_VCALLS: IGC_ASSERT(PendingTypeTestAssumeVCalls.empty()); for (unsigned I = 0; I != Record.size(); I += 2) PendingTypeTestAssumeVCalls.push_back({Record[I], Record[I+1]}); break; case bitc::FS_TYPE_CHECKED_LOAD_VCALLS: IGC_ASSERT(PendingTypeCheckedLoadVCalls.empty()); for (unsigned I = 0; I != Record.size(); I += 2) PendingTypeCheckedLoadVCalls.push_back({Record[I], Record[I+1]}); break; case bitc::FS_TYPE_TEST_ASSUME_CONST_VCALL: PendingTypeTestAssumeConstVCalls.push_back( {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; case bitc::FS_TYPE_CHECKED_LOAD_CONST_VCALL: PendingTypeCheckedLoadConstVCalls.push_back( {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; case bitc::FS_CFI_FUNCTION_DEFS: { std::set &CfiFunctionDefs = TheIndex.cfiFunctionDefs(); for (unsigned I = 0; I != Record.size(); I += 2) CfiFunctionDefs.insert( {Strtab.data() + Record[I], static_cast(Record[I + 1])}); break; } case bitc::FS_CFI_FUNCTION_DECLS: { std::set &CfiFunctionDecls = TheIndex.cfiFunctionDecls(); for (unsigned I = 0; I != Record.size(); I += 2) CfiFunctionDecls.insert( {Strtab.data() + Record[I], static_cast(Record[I + 1])}); break; } } } llvm_unreachable("Exit infinite loop"); } // Parse the module string table block into the Index. // This populates the ModulePathStringTable map in the index. Error ModuleSummaryIndexBitcodeReader::parseModuleStringTable() { if (Stream.EnterSubBlock(bitc::MODULE_STRTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; SmallString<128> ModulePath; ModuleSummaryIndex::ModuleInfo *LastSeenModule = nullptr; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::MST_CODE_ENTRY: { // MST_ENTRY: [modid, namechar x N] uint64_t ModuleId = Record[0]; if (convertToString(Record, 1, ModulePath)) return error("Invalid record"); LastSeenModule = TheIndex.addModule(ModulePath, ModuleId); ModuleIdMap[ModuleId] = LastSeenModule->first(); ModulePath.clear(); break; } /// MST_CODE_HASH: [5*i32] case bitc::MST_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); if (!LastSeenModule) return error("Invalid hash that does not follow a module path"); int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); LastSeenModule->second.second[Pos++] = Val; } // Reset LastSeenModule to avoid overriding the hash unexpectedly. LastSeenModule = nullptr; break; } } } llvm_unreachable("Exit infinite loop"); } namespace upgrader { // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. class BitcodeErrorCategoryType : public std::error_category { const char *name() const noexcept override { return "llvm.bitcode"; } std::string message(int IE) const override { BitcodeError E = static_cast(IE); switch (E) { case BitcodeError::CorruptedBitcode: return "Corrupted bitcode"; } llvm_unreachable("Unknown error type!"); } }; static ManagedStatic ErrorCategory; const std::error_category &BitcodeErrorCategory() { return *ErrorCategory; } static Expected readBlobInRecord(BitstreamCursor &Stream, unsigned Block, unsigned RecordID) { if (Stream.EnterSubBlock(Block)) return error("Invalid record"); StringRef Strtab; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: return Strtab; case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Stream.SkipBlock()) return error("Malformed block"); break; case BitstreamEntry::Record: StringRef Blob; SmallVector Record; if (Stream.readRecord(Entry.ID, Record, &Blob) == RecordID) Strtab = Blob; break; } } } //===----------------------------------------------------------------------===// // External interface //===----------------------------------------------------------------------===// Expected> getBitcodeModuleList(MemoryBufferRef Buffer) { auto FOrErr = upgrader::getBitcodeFileContents(Buffer); if (!FOrErr) return FOrErr.takeError(); return std::move(FOrErr->Mods); } Expected getBitcodeFileContents(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); BitstreamCursor &Stream = *StreamOrErr; BitcodeFileContents F; while (true) { uint64_t BCBegin = Stream.getCurrentByteNo(); // We may be consuming bitcode from a client that leaves garbage at the end // of the bitcode stream. If we are close enough to // the end that there cannot possibly be another module, stop looking. if (BCBegin + 8 >= Stream.getBitcodeBytes().size()) return F; BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: { uint64_t IdentificationBit = -1ull; if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) { IdentificationBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Stream.SkipBlock()) return error("Malformed block"); Entry = Stream.advance(); if (Entry.Kind != BitstreamEntry::SubBlock || Entry.ID != bitc::MODULE_BLOCK_ID) return error("Malformed block"); } if (Entry.ID == bitc::MODULE_BLOCK_ID) { uint64_t ModuleBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Stream.SkipBlock()) return error("Malformed block"); F.Mods.push_back({Stream.getBitcodeBytes().slice( BCBegin, Stream.getCurrentByteNo() - BCBegin), Buffer.getBufferIdentifier(), IdentificationBit, ModuleBit}); continue; } if (Entry.ID == bitc::STRTAB_BLOCK_ID) { Expected Strtab = readBlobInRecord(Stream, bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB); if (!Strtab) return Strtab.takeError(); // This string table is used by every preceding bitcode module that does // not have its own string table. A bitcode file may have multiple // string tables if it was created by binary concatenation, for example // with "llvm-cat -b". for (auto I = F.Mods.rbegin(), E = F.Mods.rend(); I != E; ++I) { if (!I->Strtab.empty()) break; I->Strtab = *Strtab; } // Similarly, the string table is used by every preceding symbol table; // normally there will be just one unless the bitcode file was created // by binary concatenation. if (!F.Symtab.empty() && F.StrtabForSymtab.empty()) F.StrtabForSymtab = *Strtab; continue; } if (Entry.ID == bitc::SYMTAB_BLOCK_ID) { Expected SymtabOrErr = readBlobInRecord(Stream, bitc::SYMTAB_BLOCK_ID, bitc::SYMTAB_BLOB); if (!SymtabOrErr) return SymtabOrErr.takeError(); // We can expect the bitcode file to have multiple symbol tables if it // was created by binary concatenation. In that case we silently // ignore any subsequent symbol tables, which is fine because this is a // low level function. The client is expected to notice that the number // of modules in the symbol table does not match the number of modules // in the input file and regenerate the symbol table. if (F.Symtab.empty()) F.Symtab = *SymtabOrErr; continue; } if (Stream.SkipBlock()) return error("Malformed block"); continue; } case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } /// \brief Get a lazy one-at-time loading module from bitcode. /// /// This isn't always used in a lazy context. In particular, it's also used by /// \a parseModule(). If this is truly lazy, then we need to eagerly pull /// in forward-referenced functions from block address references. /// /// \param[in] MaterializeAll Set to \c true if we should materialize /// everything. Expected> BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting) { BitstreamCursor Stream(Buffer); std::string ProducerIdentification; if (IdentificationBit != -1ull) { Stream.JumpToBit(IdentificationBit); Expected ProducerIdentificationOrErr = readIdentificationBlock(Stream); if (!ProducerIdentificationOrErr) return ProducerIdentificationOrErr.takeError(); ProducerIdentification = *ProducerIdentificationOrErr; } Stream.JumpToBit(ModuleBit); auto *R = new BitcodeReader(std::move(Stream), Strtab, ProducerIdentification, Context); std::unique_ptr M = llvm::make_unique(ModuleIdentifier, Context); M->setMaterializer(R); // Delay parsing Metadata if ShouldLazyLoadMetadata is true. if (Error Err = R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata, IsImporting)) return std::move(Err); if (MaterializeAll) { // Read in the entire module, and destroy the BitcodeReader. if (Error Err = M->materializeAll()) return std::move(Err); } else { // Resolve forward references from blockaddresses. if (Error Err = R->materializeForwardReferencedFunctions()) return std::move(Err); } return std::move(M); } Expected> BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { return getModuleImpl(Context, false, ShouldLazyLoadMetadata, IsImporting); } // Parse the specified bitcode buffer and merge the index into CombinedIndex. // We don't use ModuleIdentifier here because the client may need to control the // module path used in the combined summary (e.g. when reading summaries for // regular LTO modules). Error BitcodeModule::readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, uint64_t ModuleId) { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, CombinedIndex, ModulePath, ModuleId); return R.parseModule(); } // Parse the specified bitcode buffer, returning the function info index. Expected> BitcodeModule::getSummary() { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); auto Index = llvm::make_unique(false); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, *Index, ModuleIdentifier, 0); if (Error Err = R.parseModule()) return std::move(Err); return std::move(Index); } // Check if the given bitcode buffer contains a global value summary block. Expected BitcodeModule::getLTOInfo() { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false}; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true}; if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true}; // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } static Expected getSingleModule(MemoryBufferRef Buffer) { Expected> MsOrErr = upgrader::getBitcodeModuleList(Buffer); if (!MsOrErr) return MsOrErr.takeError(); if (MsOrErr->size() != 1) return error("Expected a single module"); return (*MsOrErr)[0]; } Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLazyModule(Context, ShouldLazyLoadMetadata, IsImporting); } Expected> getOwningLazyBitcodeModule( std::unique_ptr &&Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { auto MOrErr = upgrader::getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata, IsImporting); if (MOrErr) (*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer)); return MOrErr; } Expected> BitcodeModule::parseModule(LLVMContext &Context) { return getModuleImpl(Context, true, false, false); // TODO: Restore the use-lists to the in-memory state when the bitcode was // written. We must defer until the Module has been fully materialized. } Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->parseModule(Context); } Expected getBitcodeTargetTriple(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readTriple(*StreamOrErr); } Expected isBitcodeContainingObjCCategory(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return hasObjCCategory(*StreamOrErr); } Expected getBitcodeProducerString(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readIdentificationCode(*StreamOrErr); } Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, uint64_t ModuleId) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->readSummary(CombinedIndex, BM->getModuleIdentifier(), ModuleId); } Expected> getModuleSummaryIndex(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getSummary(); } Expected getBitcodeLTOInfo(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLTOInfo(); } Expected> getModuleSummaryIndexForFile(StringRef Path, bool IgnoreEmptyThinLTOIndexFile) { ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path); if (!FileOrErr) return errorCodeToError(FileOrErr.getError()); if (IgnoreEmptyThinLTOIndexFile && !(*FileOrErr)->getBufferSize()) return nullptr; return upgrader::getModuleSummaryIndex(**FileOrErr); } } // end anonymous namespaceintel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm7/BitcodeReader.h000066400000000000000000000222541363533017100272530ustar00rootroot00000000000000//===- llvm/Bitcode/BitcodeReader.h - Bitcode reader ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This header defines interfaces to read LLVM bitcode files/streams. // //===----------------------------------------------------------------------===// #ifndef __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #define __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitcode/BitCodes.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" #include #include #include #include #include namespace upgrader { using namespace llvm; struct BitcodeFileContents; /// Basic information extracted from a bitcode module to be used for LTO. struct BitcodeLTOInfo { bool IsThinLTO; bool HasSummary; }; /// Represents a module in a bitcode file. class BitcodeModule { // This covers the identification (if present) and module blocks. ArrayRef Buffer; StringRef ModuleIdentifier; // The string table used to interpret this module. StringRef Strtab; // The bitstream location of the IDENTIFICATION_BLOCK. uint64_t IdentificationBit; // The bitstream location of this module's MODULE_BLOCK. uint64_t ModuleBit; BitcodeModule(ArrayRef Buffer, StringRef ModuleIdentifier, uint64_t IdentificationBit, uint64_t ModuleBit) : Buffer(Buffer), ModuleIdentifier(ModuleIdentifier), IdentificationBit(IdentificationBit), ModuleBit(ModuleBit) {} // Calls the ctor. friend Expected getBitcodeFileContents(MemoryBufferRef Buffer); Expected> getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting); public: StringRef getBuffer() const { return StringRef((const char *)Buffer.begin(), Buffer.size()); } StringRef getStrtab() const { return Strtab; } StringRef getModuleIdentifier() const { return ModuleIdentifier; } /// Read the bitcode module and prepare for lazy deserialization of function /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well. /// If IsImporting is true, this module is being parsed for ThinLTO /// importing into another module. Expected> getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting); /// Read the entire bitcode module and return it. Expected> parseModule(LLVMContext &Context); /// Returns information about the module to be used for LTO: whether to /// compile with ThinLTO, and whether it has a summary. Expected getLTOInfo(); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getSummary(); /// Parse the specified bitcode buffer and merge its module summary index /// into CombinedIndex. Error readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, uint64_t ModuleId); }; struct BitcodeFileContents { std::vector Mods; StringRef Symtab, StrtabForSymtab; }; /// Returns the contents of a bitcode file. This includes the raw contents of /// the symbol table embedded in the bitcode file. Clients which require a /// symbol table should prefer to use irsymtab::read instead of this function /// because it creates a reader for the irsymtab and handles upgrading bitcode /// files without a symbol table or with an old symbol table. Expected getBitcodeFileContents(MemoryBufferRef Buffer); /// Returns a list of modules in the specified bitcode buffer. //Expected> //getBitcodeModuleList(MemoryBufferRef Buffer); /// Read the header of the specified bitcode buffer and prepare for lazy /// deserialization of function bodies. If ShouldLazyLoadMetadata is true, /// lazily load metadata as well. If IsImporting is true, this module is /// being parsed for ThinLTO importing into another module. Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); #if 0 /// Returns LTO information for the specified bitcode file. Expected getBitcodeLTOInfo(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getModuleSummaryIndex(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer and merge the index into CombinedIndex. Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, uint64_t ModuleId); /// Parse the module summary index out of an IR file and return the module /// summary index object if found, or an empty summary if not. If Path refers /// to an empty file and IgnoreEmptyThinLTOIndexFile is true, then /// this function will return nullptr. Expected> getModuleSummaryIndexForFile(StringRef Path, bool IgnoreEmptyThinLTOIndexFile = false); /// isBitcodeWrapper - Return true if the given bytes are the magic bytes /// for an LLVM IR bitcode wrapper. inline bool isBitcodeWrapper(const unsigned char *BufPtr, const unsigned char *BufEnd) { // See if you can find the hidden message in the magic bytes :-). // (Hint: it's a little-endian encoding.) return BufPtr != BufEnd && BufPtr[0] == 0xDE && BufPtr[1] == 0xC0 && BufPtr[2] == 0x17 && BufPtr[3] == 0x0B; } /// isRawBitcode - Return true if the given bytes are the magic bytes for /// raw LLVM IR bitcode (without a wrapper). inline bool isRawBitcode(const unsigned char *BufPtr, const unsigned char *BufEnd) { // These bytes sort of have a hidden message, but it's not in // little-endian this time, and it's a little redundant. return BufPtr != BufEnd && BufPtr[0] == 'B' && BufPtr[1] == 'C' && BufPtr[2] == 0xc0 && BufPtr[3] == 0xde; } /// isBitcode - Return true if the given bytes are the magic bytes for /// LLVM IR bitcode, either with or without a wrapper. inline bool isBitcode(const unsigned char *BufPtr, const unsigned char *BufEnd) { return isBitcodeWrapper(BufPtr, BufEnd) || isRawBitcode(BufPtr, BufEnd); } /// SkipBitcodeWrapperHeader - Some systems wrap bc files with a special /// header for padding or other reasons. The format of this header is: /// /// struct bc_header { /// uint32_t Magic; // 0x0B17C0DE /// uint32_t Version; // Version, currently always 0. /// uint32_t BitcodeOffset; // Offset to traditional bitcode file. /// uint32_t BitcodeSize; // Size of traditional bitcode file. /// ... potentially other gunk ... /// }; /// /// This function is called when we find a file with a matching magic number. /// In this case, skip down to the subsection of the file that is actually a /// BC file. /// If 'VerifyBufferSize' is true, check that the buffer is large enough to /// contain the whole bitcode file. inline bool SkipBitcodeWrapperHeader(const unsigned char *&BufPtr, const unsigned char *&BufEnd, bool VerifyBufferSize) { // Must contain the offset and size field! if (unsigned(BufEnd - BufPtr) < BWH_SizeField + 4) return true; unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]); unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]); uint64_t BitcodeOffsetEnd = (uint64_t)Offset + (uint64_t)Size; // Verify that Offset+Size fits in the file. if (VerifyBufferSize && BitcodeOffsetEnd > uint64_t(BufEnd-BufPtr)) return true; BufPtr += Offset; BufEnd = BufPtr+Size; return false; } const std::error_category &BitcodeErrorCategory(); enum class BitcodeError { CorruptedBitcode = 1 }; inline std::error_code make_error_code(BitcodeError E) { return std::error_code(static_cast(E), BitcodeErrorCategory()); } #endif } // end namespace llvm #endif // LLVM_BITCODE_BITCODEREADER_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm7/MetadataLoader.h000066400000000000000000000051571363533017100274310ustar00rootroot00000000000000//===-- Bitcode/Reader/MetadataLoader.h - Load Metadatas -------*- C++ -*-====// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class handles loading Metadatas. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_METADATALOADER_H #define LLVM_LIB_BITCODE_READER_METADATALOADER_H #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Error.h" #include #include namespace llvm { class BitcodeReaderValueList; class BitstreamCursor; class DISubprogram; class Error; class Function; class Instruction; class Metadata; class MDNode; class Module; class Type; /// Helper class that handles loading Metadatas and keeping them available. class MetadataLoader { class MetadataLoaderImpl; std::unique_ptr Pimpl; Error parseMetadata(bool ModuleLevel); public: ~MetadataLoader(); MetadataLoader(BitstreamCursor &Stream, Module &TheModule, BitcodeReaderValueList &ValueList, bool IsImporting, std::function getTypeByID); MetadataLoader &operator=(MetadataLoader &&); MetadataLoader(MetadataLoader &&); // Parse a module metadata block Error parseModuleMetadata() { return parseMetadata(true); } // Parse a function metadata block Error parseFunctionMetadata() { return parseMetadata(false); } /// Set the mode to strip TBAA metadata on load. void setStripTBAA(bool StripTBAA = true); /// Return true if the Loader is stripping TBAA metadata. bool isStrippingTBAA(); // Return true there are remaining unresolved forward references. bool hasFwdRefs() const; /// Return the given metadata, creating a replaceable forward reference if /// necessary. Metadata *getMetadataFwdRefOrLoad(unsigned Idx); MDNode *getMDNodeFwdRefOrNull(unsigned Idx); /// Return the DISubprogra metadata for a Function if any, null otherwise. DISubprogram *lookupSubprogramForFunction(Function *F); /// Parse a `METADATA_ATTACHMENT` block for a function. Error parseMetadataAttachment( Function &F, const SmallVectorImpl &InstructionList); /// Parse a `METADATA_KIND` block for the current module. Error parseMetadataKinds(); unsigned size() const; void shrinkTo(unsigned N); /// Perform bitcode upgrades on llvm.dbg.* calls. void upgradeDebugIntrinsics(Function &F); }; } #endif // LLVM_LIB_BITCODE_READER_METADATALOADER_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm7/Upgrader.cpp000066400000000000000000000043221363533017100266570ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "Upgrader.h" #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include #include #include "common/LLVMWarningsPop.hpp" using namespace llvm; std::unique_ptr upgrader::upgradeBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { auto ErrM = upgrader::parseBitcodeFile(Buffer, Context); Module *M = ErrM.get().get(); if (!M) return nullptr; SmallVector Buf; Buf.reserve(1024*1024); raw_svector_ostream OS(Buf); WriteBitcodeToFile(*M, OS); return MemoryBuffer::getMemBufferCopy(OS.str()); } Expected> upgrader::upgradeAndParseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { return upgrader::parseBitcodeFile(Buffer, Context); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm7/Upgrader.h000066400000000000000000000036741363533017100263350ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #ifndef __DRIVERINTERFACE_UPGRADER_H__ #define __DRIVERINTERFACE_UPGRADER_H__ #include "common/LLVMWarningsPush.hpp" #include #include #include #include #include "common/LLVMWarningsPop.hpp" namespace upgrader { llvm::Expected> parseBitcodeFile(llvm::MemoryBufferRef Buffer, llvm::LLVMContext &Context); std::unique_ptr upgradeBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); llvm::Expected> upgradeAndParseBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); } // End upgrader namespace #endif // __DRIVERINTERFACE_UPGRADER_H__ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm7/ValueList.h000066400000000000000000000050121363533017100264600ustar00rootroot00000000000000//===-- Bitcode/Reader/ValueList.h - Number values --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class gives values and types Unique ID's. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_VALUELIST_H #define LLVM_LIB_BITCODE_READER_VALUELIST_H #include "llvm/IR/ValueHandle.h" #include #include #include "Probe.h" namespace llvm { class Constant; class LLVMContext; class Type; class Value; class BitcodeReaderValueList { std::vector ValuePtrs; /// As we resolve forward-referenced constants, we add information about them /// to this vector. This allows us to resolve them in bulk instead of /// resolving each reference at a time. See the code in /// ResolveConstantForwardRefs for more information about this. /// /// The key of this vector is the placeholder constant, the value is the slot /// number that holds the resolved value. using ResolveConstantsTy = std::vector>; ResolveConstantsTy ResolveConstants; LLVMContext &Context; public: BitcodeReaderValueList(LLVMContext &C) : Context(C) {} ~BitcodeReaderValueList() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); } // vector compatibility methods unsigned size() const { return ValuePtrs.size(); } void resize(unsigned N) { ValuePtrs.resize(N); } void push_back(Value *V) { ValuePtrs.emplace_back(V); } void clear() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); ValuePtrs.clear(); } Value *operator[](unsigned i) const { IGC_ASSERT(i < ValuePtrs.size()); return ValuePtrs[i]; } Value *back() const { return ValuePtrs.back(); } void pop_back() { ValuePtrs.pop_back(); } bool empty() const { return ValuePtrs.empty(); } void shrinkTo(unsigned N) { IGC_ASSERT(N <= size() && "Invalid shrinkTo request!"); ValuePtrs.resize(N); } Constant *getConstantFwdRef(unsigned Idx, Type *Ty); Value *getValueFwdRef(unsigned Idx, Type *Ty); void assignValue(Value *V, unsigned Idx); /// Once all constants are read, this method bulk resolves any forward /// references. void resolveConstantForwardRefs(); }; } // end namespace llvm #endif // LLVM_LIB_BITCODE_READER_VALUELIST_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm8/000077500000000000000000000000001363533017100244025ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm8/BitcodeReader.cpp000066400000000000000000006727341363533017100276250ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "MetadataLoader.h" #include "ValueList.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalIndirectSymbol.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "common/LLVMWarningsPop.hpp" #include "BitcodeReader.h" #include "Probe.h" using namespace llvm; //===----------------------------------------------------------------------===// // upgrade bitcast to addrspacecast when necessary //===----------------------------------------------------------------------===// Instruction *upgradeBitCastInst(unsigned Opc, Value *V, Type *DestTy, Instruction *&Temp) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = V->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return CastInst::Create(Instruction::AddrSpaceCast, V, DestTy); } return nullptr; } Value *upgradeBitCastExpr(unsigned Opc, Constant *C, Type *DestTy) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = C->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return ConstantExpr::getAddrSpaceCast(C, DestTy); } return nullptr; } namespace { enum { SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; } // end anonymous namespace static Error error(const Twine &Message) { return make_error( Message, make_error_code(BitcodeError::CorruptedBitcode)); } /// Helper to read the header common to all bitcode files. static bool hasValidBitcodeHeader(BitstreamCursor &Stream) { // Sniff for the signature. if (!Stream.canSkipToPos(4) || Stream.Read(8) != 'B' || Stream.Read(8) != 'C' || Stream.Read(4) != 0x0 || Stream.Read(4) != 0xC || Stream.Read(4) != 0xE || Stream.Read(4) != 0xD) return false; return true; } static Expected initStream(MemoryBufferRef Buffer) { const unsigned char *BufPtr = (const unsigned char *)Buffer.getBufferStart(); const unsigned char *BufEnd = BufPtr + Buffer.getBufferSize(); if (Buffer.getBufferSize() & 3) return error("Invalid bitcode signature"); // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. if (isBitcodeWrapper(BufPtr, BufEnd)) if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) return error("Invalid bitcode wrapper header"); BitstreamCursor Stream(ArrayRef(BufPtr, BufEnd)); if (!hasValidBitcodeHeader(Stream)) return error("Invalid bitcode signature"); return std::move(Stream); } /// Convert a string from a record into an std::string, return true on failure. template static bool convertToString(ArrayRef Record, unsigned Idx, StrTy &Result) { if (Idx > Record.size()) return true; for (unsigned i = Idx, e = Record.size(); i != e; ++i) Result += (char)Record[i]; return false; } // Strip all the TBAA attachment for the module. static void stripTBAA(Module *M) { for (auto &F : *M) { if (F.isMaterializable()) continue; for (auto &I : instructions(F)) I.setMetadata(LLVMContext::MD_tbaa, nullptr); } } /// Read the "IDENTIFICATION_BLOCK_ID" block, do some basic enforcement on the /// "epoch" encoded in the bitcode, and return the producer name if any. static Expected readIdentificationBlock(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::IDENTIFICATION_BLOCK_ID)) return error("Invalid record"); // Read all the records. SmallVector Record; std::string ProducerIdentification; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { default: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ProducerIdentification; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: reject return error("Invalid value"); case bitc::IDENTIFICATION_CODE_STRING: // IDENTIFICATION: [strchr x N] convertToString(Record, 0, ProducerIdentification); break; case bitc::IDENTIFICATION_CODE_EPOCH: { // EPOCH: [epoch#] unsigned epoch = (unsigned)Record[0]; if (epoch != bitc::BITCODE_CURRENT_EPOCH) { return error( Twine("Incompatible epoch: Bitcode '") + Twine(epoch) + "' vs current: '" + Twine(bitc::BITCODE_CURRENT_EPOCH) + "'"); } } } } } static Expected readIdentificationCode(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { if (Stream.AtEndOfStream()) return ""; BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) return readIdentificationBlock(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } static Expected hasObjCCategoryInModule(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. switch (Stream.readRecord(Entry.ID, Record)) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Check for the i386 and other (x86_64, ARM) conventions if (S.find("__DATA,__objc_catlist") != std::string::npos || S.find("__OBJC,__category") != std::string::npos) return true; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } static Expected hasObjCCategory(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return hasObjCCategoryInModule(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } static Expected readModuleTriple(BitstreamCursor &Stream) { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; std::string Triple; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Triple; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. switch (Stream.readRecord(Entry.ID, Record)) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); Triple = S; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } static Expected readTriple(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ""; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return readModuleTriple(Stream); // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } namespace { class BitcodeReaderBase { protected: BitcodeReaderBase(BitstreamCursor Stream, StringRef Strtab) : Stream(std::move(Stream)), Strtab(Strtab) { this->Stream.setBlockInfo(&BlockInfo); } BitstreamBlockInfo BlockInfo; BitstreamCursor Stream; StringRef Strtab; /// In version 2 of the bitcode we store names of global values and comdats in /// a string table rather than in the VST. bool UseStrtab = false; Expected parseVersionRecord(ArrayRef Record); /// If this module uses a string table, pop the reference to the string table /// and return the referenced string and the rest of the record. Otherwise /// just return the record itself. std::pair> readNameFromStrtab(ArrayRef Record); bool readBlockInfo(); // Contains an arbitrary and optional string identifying the bitcode producer std::string ProducerIdentification; Error error(const Twine &Message); }; } // end anonymous namespace Error BitcodeReaderBase::error(const Twine &Message) { std::string FullMsg = Message.str(); if (!ProducerIdentification.empty()) FullMsg += " (Producer: '" + ProducerIdentification + "' Reader: 'LLVM " + LLVM_VERSION_STRING "')"; return ::error(FullMsg); } Expected BitcodeReaderBase::parseVersionRecord(ArrayRef Record) { if (Record.empty()) return error("Invalid record"); unsigned ModuleVersion = Record[0]; if (ModuleVersion > 2) return error("Invalid value"); UseStrtab = ModuleVersion >= 2; return ModuleVersion; } std::pair> BitcodeReaderBase::readNameFromStrtab(ArrayRef Record) { if (!UseStrtab) return {"", Record}; // Invalid reference. Let the caller complain about the record being empty. if (Record[0] + Record[1] > Strtab.size()) return {"", {}}; return {StringRef(Strtab.data() + Record[0], Record[1]), Record.slice(2)}; } namespace { class BitcodeReader : public BitcodeReaderBase, public GVMaterializer { LLVMContext &Context; Module *TheModule = nullptr; // Next offset to start scanning for lazy parsing of function bodies. uint64_t NextUnreadBit = 0; // Last function offset found in the VST. uint64_t LastFunctionBlockBit = 0; bool SeenValueSymbolTable = false; uint64_t VSTOffset = 0; std::vector SectionTable; std::vector GCTable; std::vector TypeList; BitcodeReaderValueList ValueList; Optional MDLoader; std::vector ComdatList; SmallVector InstructionList; std::vector> GlobalInits; std::vector> IndirectSymbolInits; std::vector> FunctionPrefixes; std::vector> FunctionPrologues; std::vector> FunctionPersonalityFns; /// The set of attributes by index. Index zero in the file is for null, and /// is thus not represented here. As such all indices are off by one. std::vector MAttributes; /// The set of attribute groups. std::map MAttributeGroups; /// While parsing a function body, this is a list of the basic blocks for the /// function. std::vector FunctionBBs; // When reading the module header, this list is populated with functions that // have bodies later in the file. std::vector FunctionsWithBodies; // When intrinsic functions are encountered which require upgrading they are // stored here with their replacement function. using UpdatedIntrinsicMap = DenseMap; UpdatedIntrinsicMap UpgradedIntrinsics; // Intrinsics which were remangled because of types rename UpdatedIntrinsicMap RemangledIntrinsics; // Several operations happen after the module header has been read, but // before function bodies are processed. This keeps track of whether // we've done this yet. bool SeenFirstFunctionBody = false; /// When function bodies are initially scanned, this map contains info about /// where to find deferred function body in the stream. DenseMap DeferredFunctionInfo; /// When Metadata block is initially scanned when parsing the module, we may /// choose to defer parsing of the metadata. This vector contains info about /// which Metadata blocks are deferred. std::vector DeferredMetadataInfo; /// These are basic blocks forward-referenced by block addresses. They are /// inserted lazily into functions when they're loaded. The basic block ID is /// its index into the vector. DenseMap> BasicBlockFwdRefs; std::deque BasicBlockFwdRefQueue; /// Indicates that we are using a new encoding for instruction operands where /// most operands in the current FUNCTION_BLOCK are encoded relative to the /// instruction number, for a more compact encoding. Some instruction /// operands are not relative to the instruction ID: basic block numbers, and /// types. Once the old style function blocks have been phased out, we would /// not need this flag. bool UseRelativeIDs = false; /// True if all functions will be materialized, negating the need to process /// (e.g.) blockaddress forward references. bool WillMaterializeAllForwardRefs = false; bool StripDebugInfo = false; TBAAVerifier TBAAVerifyHelper; std::vector BundleTags; SmallVector SSIDs; public: BitcodeReader(BitstreamCursor Stream, StringRef Strtab, StringRef ProducerIdentification, LLVMContext &Context); Error materializeForwardReferencedFunctions(); Error materialize(GlobalValue *GV) override; Error materializeModule() override; std::vector getIdentifiedStructTypes() const override; /// Main interface to parsing a bitcode buffer. /// \returns true if an error occurred. Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); static uint64_t decodeSignRotatedValue(uint64_t V); /// Materialize any deferred Metadata block. Error materializeMetadata() override; void setStripDebugInfo() override; private: std::vector IdentifiedStructTypes; StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); StructType *createIdentifiedStructType(LLVMContext &Context); Type *getTypeByID(unsigned ID); Value *getFnValueByID(unsigned ID, Type *Ty) { if (Ty && Ty->isMetadataTy()) return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); return ValueList.getValueFwdRef(ID, Ty); } Metadata *getFnMetadataByID(unsigned ID) { return MDLoader->getMetadataFwdRefOrLoad(ID); } BasicBlock *getBasicBlock(unsigned ID) const { if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID return FunctionBBs[ID]; } AttributeList getAttributes(unsigned i) const { if (i-1 < MAttributes.size()) return MAttributes[i-1]; return AttributeList(); } /// Read a value/type pair out of the specified record from slot 'Slot'. /// Increment Slot past the number of slots used in the record. Return true on /// failure. bool getValueTypePair(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Value *&ResVal) { if (Slot == Record.size()) return true; unsigned ValNo = (unsigned)Record[Slot++]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; if (ValNo < InstNum) { // If this is not a forward reference, just return the value we already // have. ResVal = getFnValueByID(ValNo, nullptr); return ResVal == nullptr; } if (Slot == Record.size()) return true; unsigned TypeNo = (unsigned)Record[Slot++]; ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo)); return ResVal == nullptr; } /// Read a value out of the specified record from slot 'Slot'. Increment Slot /// past the number of slots used by the value in the record. Return true if /// there is an error. bool popValue(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { if (getValue(Record, Slot, InstNum, Ty, ResVal)) return true; // All values currently take a single record slot. ++Slot; return false; } /// Like popValue, but does not increment the Slot number. bool getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { ResVal = getValue(Record, Slot, InstNum, Ty); return ResVal == nullptr; } /// Version of getValue that returns ResVal directly, or 0 if there is an /// error. Value *getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)Record[Slot]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Like getValue, but decodes signed VBRs. Value *getValueSigned(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)decodeSignRotatedValue(Record[Slot]); // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Converts alignment exponent (i.e. power of two (or zero)) to the /// corresponding alignment to use. If alignment is too large, returns /// a corresponding error code. Error parseAlignmentValue(uint64_t Exponent, unsigned &Alignment); Error parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind); Error parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata = false); Error parseComdatRecord(ArrayRef Record); Error parseGlobalVarRecord(ArrayRef Record); Error parseFunctionRecord(ArrayRef Record); Error parseGlobalIndirectSymbolRecord(unsigned BitCode, ArrayRef Record); Error parseAttributeBlock(); Error parseAttributeGroupBlock(); Error parseTypeTable(); Error parseTypeTableBody(); Error parseOperandBundleTags(); Error parseSyncScopeNames(); Expected recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT); void setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F, ArrayRef Record); Error parseValueSymbolTable(uint64_t Offset = 0); Error parseGlobalValueSymbolTable(); Error parseConstants(); Error rememberAndSkipFunctionBodies(); Error rememberAndSkipFunctionBody(); /// Save the positions of the Metadata blocks and skip parsing the blocks. Error rememberAndSkipMetadata(); Error typeCheckLoadStoreInst(Type *ValType, Type *PtrType); Error parseFunctionBody(Function *F); Error globalCleanup(); Error resolveGlobalAndIndirectSymbolInits(); Error parseUseLists(); Error findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator); SyncScope::ID getDecodedSyncScopeID(unsigned Val); }; /// Class to manage reading and parsing function summary index bitcode /// files/sections. class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase { /// The module index built during parsing. ModuleSummaryIndex &TheIndex; /// Indicates whether we have encountered a global value summary section /// yet during parsing. bool SeenGlobalValSummary = false; /// Indicates whether we have already parsed the VST, used for error checking. bool SeenValueSymbolTable = false; /// Set to the offset of the VST recorded in the MODULE_CODE_VSTOFFSET record. /// Used to enable on-demand parsing of the VST. uint64_t VSTOffset = 0; // Map to save ValueId to ValueInfo association that was recorded in the // ValueSymbolTable. It is used after the VST is parsed to convert // call graph edges read from the function summary from referencing // callees by their ValueId to using the ValueInfo instead, which is how // they are recorded in the summary index being built. // We save a GUID which refers to the same global as the ValueInfo, but // ignoring the linkage, i.e. for values other than local linkage they are // identical. DenseMap> ValueIdToValueInfoMap; /// Map populated during module path string table parsing, from the /// module ID to a string reference owned by the index's module /// path string table, used to correlate with combined index /// summary records. DenseMap ModuleIdMap; /// Original source file name recorded in a bitcode record. std::string SourceFileName; /// The string identifier given to this module by the client, normally the /// path to the bitcode file. StringRef ModulePath; /// For per-module summary indexes, the unique numerical identifier given to /// this module by the client. unsigned ModuleId; public: ModuleSummaryIndexBitcodeReader(BitstreamCursor Stream, StringRef Strtab, ModuleSummaryIndex &TheIndex, StringRef ModulePath, unsigned ModuleId); Error parseModule(); private: void setValueGUID(uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage, StringRef SourceFileName); Error parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap); std::vector makeRefList(ArrayRef Record); std::vector makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile, bool HasRelBF); Error parseEntireSummary(unsigned ID); Error parseModuleStringTable(); std::pair getValueInfoFromValueId(unsigned ValueId); void addThisModule(); ModuleSummaryIndex::ModuleInfo *getThisModule(); }; } // end anonymous namespace #if 0 std::error_code llvm::errorToErrorCodeAndEmitErrors(LLVMContext &Ctx, Error Err) { if (Err) { std::error_code EC; handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { EC = EIB.convertToErrorCode(); Ctx.emitError(EIB.message()); }); return EC; } return std::error_code(); } #endif BitcodeReader::BitcodeReader(BitstreamCursor Stream, StringRef Strtab, StringRef ProducerIdentification, LLVMContext &Context) : BitcodeReaderBase(std::move(Stream), Strtab), Context(Context), ValueList(Context) { this->ProducerIdentification = ProducerIdentification; } Error BitcodeReader::materializeForwardReferencedFunctions() { if (WillMaterializeAllForwardRefs) return Error::success(); // Prevent recursion. WillMaterializeAllForwardRefs = true; while (!BasicBlockFwdRefQueue.empty()) { Function *F = BasicBlockFwdRefQueue.front(); BasicBlockFwdRefQueue.pop_front(); IGC_ASSERT(F && "Expected valid function"); if (!BasicBlockFwdRefs.count(F)) // Already materialized. continue; // Check for a function that isn't materializable to prevent an infinite // loop. When parsing a blockaddress stored in a global variable, there // isn't a trivial way to check if a function will have a body without a // linear search through FunctionsWithBodies, so just check it here. if (!F->isMaterializable()) return error("Never resolved function from blockaddress"); // Try to materialize F. if (Error Err = materialize(F)) return Err; } IGC_ASSERT(BasicBlockFwdRefs.empty() && "Function missing from queue"); // Reset state. WillMaterializeAllForwardRefs = false; return Error::success(); } //===----------------------------------------------------------------------===// // Helper functions to implement forward reference resolution, etc. //===----------------------------------------------------------------------===// static bool hasImplicitComdat(size_t Val) { switch (Val) { default: return false; case 1: // Old WeakAnyLinkage case 4: // Old LinkOnceAnyLinkage case 10: // Old WeakODRLinkage case 11: // Old LinkOnceODRLinkage return true; } } static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) { switch (Val) { default: // Map unknown/new linkages to external case 0: return GlobalValue::ExternalLinkage; case 2: return GlobalValue::AppendingLinkage; case 3: return GlobalValue::InternalLinkage; case 5: return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage case 6: return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage case 7: return GlobalValue::ExternalWeakLinkage; case 8: return GlobalValue::CommonLinkage; case 9: return GlobalValue::PrivateLinkage; case 12: return GlobalValue::AvailableExternallyLinkage; case 13: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage case 14: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateWeakLinkage case 15: return GlobalValue::ExternalLinkage; // Obsolete LinkOnceODRAutoHideLinkage case 1: // Old value with implicit comdat. case 16: return GlobalValue::WeakAnyLinkage; case 10: // Old value with implicit comdat. case 17: return GlobalValue::WeakODRLinkage; case 4: // Old value with implicit comdat. case 18: return GlobalValue::LinkOnceAnyLinkage; case 11: // Old value with implicit comdat. case 19: return GlobalValue::LinkOnceODRLinkage; } } static FunctionSummary::FFlags getDecodedFFlags(uint64_t RawFlags) { FunctionSummary::FFlags Flags; Flags.ReadNone = RawFlags & 0x1; Flags.ReadOnly = (RawFlags >> 1) & 0x1; Flags.NoRecurse = (RawFlags >> 2) & 0x1; Flags.ReturnDoesNotAlias = (RawFlags >> 3) & 0x1; Flags.NoInline = (RawFlags >> 4) & 0x1; return Flags; } /// Decode the flags for GlobalValue in the summary. static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags, uint64_t Version) { // Summary were not emitted before LLVM 3.9, we don't need to upgrade Linkage // like getDecodedLinkage() above. Any future change to the linkage enum and // to getDecodedLinkage() will need to be taken into account here as above. auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits RawFlags = RawFlags >> 4; bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3; // The Live flag wasn't introduced until version 3. For dead stripping // to work correctly on earlier versions, we must conservatively treat all // values as live. bool Live = (RawFlags & 0x2) || Version < 3; bool Local = (RawFlags & 0x4); return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live, Local); } // Decode the flags for GlobalVariable in the summary static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) { return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { switch (Val) { default: // Map unknown visibilities to default. case 0: return GlobalValue::DefaultVisibility; case 1: return GlobalValue::HiddenVisibility; case 2: return GlobalValue::ProtectedVisibility; } } static GlobalValue::DLLStorageClassTypes getDecodedDLLStorageClass(unsigned Val) { switch (Val) { default: // Map unknown values to default. case 0: return GlobalValue::DefaultStorageClass; case 1: return GlobalValue::DLLImportStorageClass; case 2: return GlobalValue::DLLExportStorageClass; } } static bool getDecodedDSOLocal(unsigned Val) { switch(Val) { default: // Map unknown values to preemptable. case 0: return false; case 1: return true; } } static GlobalVariable::ThreadLocalMode getDecodedThreadLocalMode(unsigned Val) { switch (Val) { case 0: return GlobalVariable::NotThreadLocal; default: // Map unknown non-zero value to general dynamic. case 1: return GlobalVariable::GeneralDynamicTLSModel; case 2: return GlobalVariable::LocalDynamicTLSModel; case 3: return GlobalVariable::InitialExecTLSModel; case 4: return GlobalVariable::LocalExecTLSModel; } } static GlobalVariable::UnnamedAddr getDecodedUnnamedAddrType(unsigned Val) { switch (Val) { default: // Map unknown to UnnamedAddr::None. case 0: return GlobalVariable::UnnamedAddr::None; case 1: return GlobalVariable::UnnamedAddr::Global; case 2: return GlobalVariable::UnnamedAddr::Local; } } static int getDecodedCastOpcode(unsigned Val) { switch (Val) { default: return -1; case bitc::CAST_TRUNC : return Instruction::Trunc; case bitc::CAST_ZEXT : return Instruction::ZExt; case bitc::CAST_SEXT : return Instruction::SExt; case bitc::CAST_FPTOUI : return Instruction::FPToUI; case bitc::CAST_FPTOSI : return Instruction::FPToSI; case bitc::CAST_UITOFP : return Instruction::UIToFP; case bitc::CAST_SITOFP : return Instruction::SIToFP; case bitc::CAST_FPTRUNC : return Instruction::FPTrunc; case bitc::CAST_FPEXT : return Instruction::FPExt; case bitc::CAST_PTRTOINT: return Instruction::PtrToInt; case bitc::CAST_INTTOPTR: return Instruction::IntToPtr; case bitc::CAST_BITCAST : return Instruction::BitCast; case bitc::CAST_ADDRSPACECAST: return Instruction::AddrSpaceCast; } } static int getDecodedUnaryOpcode(unsigned Val, Type *Ty) { bool IsFP = Ty->isFPOrFPVectorTy(); // UnOps are only valid for int/fp or vector of int/fp types if (!IsFP && !Ty->isIntOrIntVectorTy()) return -1; switch (Val) { default: return -1; case bitc::UNOP_NEG: return IsFP ? Instruction::FNeg : -1; } } static int getDecodedBinaryOpcode(unsigned Val, Type *Ty) { bool IsFP = Ty->isFPOrFPVectorTy(); // BinOps are only valid for int/fp or vector of int/fp types if (!IsFP && !Ty->isIntOrIntVectorTy()) return -1; switch (Val) { default: return -1; case bitc::BINOP_ADD: return IsFP ? Instruction::FAdd : Instruction::Add; case bitc::BINOP_SUB: return IsFP ? Instruction::FSub : Instruction::Sub; case bitc::BINOP_MUL: return IsFP ? Instruction::FMul : Instruction::Mul; case bitc::BINOP_UDIV: return IsFP ? -1 : Instruction::UDiv; case bitc::BINOP_SDIV: return IsFP ? Instruction::FDiv : Instruction::SDiv; case bitc::BINOP_UREM: return IsFP ? -1 : Instruction::URem; case bitc::BINOP_SREM: return IsFP ? Instruction::FRem : Instruction::SRem; case bitc::BINOP_SHL: return IsFP ? -1 : Instruction::Shl; case bitc::BINOP_LSHR: return IsFP ? -1 : Instruction::LShr; case bitc::BINOP_ASHR: return IsFP ? -1 : Instruction::AShr; case bitc::BINOP_AND: return IsFP ? -1 : Instruction::And; case bitc::BINOP_OR: return IsFP ? -1 : Instruction::Or; case bitc::BINOP_XOR: return IsFP ? -1 : Instruction::Xor; } } static AtomicRMWInst::BinOp getDecodedRMWOperation(unsigned Val) { switch (Val) { default: return AtomicRMWInst::BAD_BINOP; case bitc::RMW_XCHG: return AtomicRMWInst::Xchg; case bitc::RMW_ADD: return AtomicRMWInst::Add; case bitc::RMW_SUB: return AtomicRMWInst::Sub; case bitc::RMW_AND: return AtomicRMWInst::And; case bitc::RMW_NAND: return AtomicRMWInst::Nand; case bitc::RMW_OR: return AtomicRMWInst::Or; case bitc::RMW_XOR: return AtomicRMWInst::Xor; case bitc::RMW_MAX: return AtomicRMWInst::Max; case bitc::RMW_MIN: return AtomicRMWInst::Min; case bitc::RMW_UMAX: return AtomicRMWInst::UMax; case bitc::RMW_UMIN: return AtomicRMWInst::UMin; } } static AtomicOrdering getDecodedOrdering(unsigned Val) { switch (Val) { case bitc::ORDERING_NOTATOMIC: return AtomicOrdering::NotAtomic; case bitc::ORDERING_UNORDERED: return AtomicOrdering::Unordered; case bitc::ORDERING_MONOTONIC: return AtomicOrdering::Monotonic; case bitc::ORDERING_ACQUIRE: return AtomicOrdering::Acquire; case bitc::ORDERING_RELEASE: return AtomicOrdering::Release; case bitc::ORDERING_ACQREL: return AtomicOrdering::AcquireRelease; default: // Map unknown orderings to sequentially-consistent. case bitc::ORDERING_SEQCST: return AtomicOrdering::SequentiallyConsistent; } } static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) { switch (Val) { default: // Map unknown selection kinds to any. case bitc::COMDAT_SELECTION_KIND_ANY: return Comdat::Any; case bitc::COMDAT_SELECTION_KIND_EXACT_MATCH: return Comdat::ExactMatch; case bitc::COMDAT_SELECTION_KIND_LARGEST: return Comdat::Largest; case bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES: return Comdat::NoDuplicates; case bitc::COMDAT_SELECTION_KIND_SAME_SIZE: return Comdat::SameSize; } } static FastMathFlags getDecodedFastMathFlags(unsigned Val) { FastMathFlags FMF; if (0 != (Val & bitc::UnsafeAlgebra)) FMF.setFast(); if (0 != (Val & bitc::AllowReassoc)) FMF.setAllowReassoc(); if (0 != (Val & bitc::NoNaNs)) FMF.setNoNaNs(); if (0 != (Val & bitc::NoInfs)) FMF.setNoInfs(); if (0 != (Val & bitc::NoSignedZeros)) FMF.setNoSignedZeros(); if (0 != (Val & bitc::AllowReciprocal)) FMF.setAllowReciprocal(); if (0 != (Val & bitc::AllowContract)) FMF.setAllowContract(true); if (0 != (Val & bitc::ApproxFunc)) FMF.setApproxFunc(); return FMF; } static void upgradeDLLImportExportLinkage(GlobalValue *GV, unsigned Val) { switch (Val) { case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break; case 6: GV->setDLLStorageClass(GlobalValue::DLLExportStorageClass); break; } } Type *BitcodeReader::getTypeByID(unsigned ID) { // The type table size is always specified correctly. if (ID >= TypeList.size()) return nullptr; if (Type *Ty = TypeList[ID]) return Ty; // If we have a forward reference, the only possible case is when it is to a // named struct. Just create a placeholder for now. return TypeList[ID] = createIdentifiedStructType(Context); } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context, StringRef Name) { auto *Ret = StructType::create(Context, Name); IdentifiedStructTypes.push_back(Ret); return Ret; } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) { auto *Ret = StructType::create(Context); IdentifiedStructTypes.push_back(Ret); return Ret; } //===----------------------------------------------------------------------===// // Functions for parsing blocks from the bitcode file //===----------------------------------------------------------------------===// static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { switch (Val) { case Attribute::EndAttrKinds: llvm_unreachable("Synthetic enumerators which should never get here"); case Attribute::None: return 0; case Attribute::ZExt: return 1 << 0; case Attribute::SExt: return 1 << 1; case Attribute::NoReturn: return 1 << 2; case Attribute::InReg: return 1 << 3; case Attribute::StructRet: return 1 << 4; case Attribute::NoUnwind: return 1 << 5; case Attribute::NoAlias: return 1 << 6; case Attribute::ByVal: return 1 << 7; case Attribute::Nest: return 1 << 8; case Attribute::ReadNone: return 1 << 9; case Attribute::ReadOnly: return 1 << 10; case Attribute::NoInline: return 1 << 11; case Attribute::AlwaysInline: return 1 << 12; case Attribute::OptimizeForSize: return 1 << 13; case Attribute::StackProtect: return 1 << 14; case Attribute::StackProtectReq: return 1 << 15; case Attribute::Alignment: return 31 << 16; case Attribute::NoCapture: return 1 << 21; case Attribute::NoRedZone: return 1 << 22; case Attribute::NoImplicitFloat: return 1 << 23; case Attribute::Naked: return 1 << 24; case Attribute::InlineHint: return 1 << 25; case Attribute::StackAlignment: return 7 << 26; case Attribute::ReturnsTwice: return 1 << 29; case Attribute::UWTable: return 1 << 30; case Attribute::NonLazyBind: return 1U << 31; case Attribute::SanitizeAddress: return 1ULL << 32; case Attribute::MinSize: return 1ULL << 33; case Attribute::NoDuplicate: return 1ULL << 34; case Attribute::StackProtectStrong: return 1ULL << 35; case Attribute::SanitizeThread: return 1ULL << 36; case Attribute::SanitizeMemory: return 1ULL << 37; case Attribute::NoBuiltin: return 1ULL << 38; case Attribute::Returned: return 1ULL << 39; case Attribute::Cold: return 1ULL << 40; case Attribute::Builtin: return 1ULL << 41; case Attribute::OptimizeNone: return 1ULL << 42; case Attribute::InAlloca: return 1ULL << 43; case Attribute::NonNull: return 1ULL << 44; case Attribute::JumpTable: return 1ULL << 45; case Attribute::Convergent: return 1ULL << 46; case Attribute::SafeStack: return 1ULL << 47; case Attribute::NoRecurse: return 1ULL << 48; case Attribute::InaccessibleMemOnly: return 1ULL << 49; case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50; case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; case Attribute::WriteOnly: return 1ULL << 53; case Attribute::Speculatable: return 1ULL << 54; case Attribute::StrictFP: return 1ULL << 55; case Attribute::SanitizeHWAddress: return 1ULL << 56; case Attribute::NoCfCheck: return 1ULL << 57; case Attribute::OptForFuzzing: return 1ULL << 58; case Attribute::ShadowCallStack: return 1ULL << 59; case Attribute::SpeculativeLoadHardening: return 1ULL << 60; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; case Attribute::DereferenceableOrNull: llvm_unreachable("dereferenceable_or_null attribute not supported in raw " "format"); break; case Attribute::ArgMemOnly: llvm_unreachable("argmemonly attribute not supported in raw format"); break; case Attribute::AllocSize: llvm_unreachable("allocsize not supported in raw format"); break; default: llvm_unreachable("Unsupported attribute type"); break; //return 0; } } static void addRawAttributeValue(AttrBuilder &B, uint64_t Val) { if (!Val) return; for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; I = Attribute::AttrKind(I + 1)) { if (I == Attribute::Dereferenceable || I == Attribute::DereferenceableOrNull || I == Attribute::ArgMemOnly || I == Attribute::AllocSize) continue; if (uint64_t A = (Val & getRawAttributeMask(I))) { if (I == Attribute::Alignment) B.addAlignmentAttr(1ULL << ((A >> 16) - 1)); else if (I == Attribute::StackAlignment) B.addStackAlignmentAttr(1ULL << ((A >> 26)-1)); else B.addAttribute(I); } } } /// This fills an AttrBuilder object with the LLVM attributes that have /// been decoded from the given integer. This function must stay in sync with /// 'encodeLLVMAttributesForBitcode'. static void decodeLLVMAttributesForBitcode(AttrBuilder &B, uint64_t EncodedAttrs) { // FIXME: Remove in 4.0. // The alignment is stored as a 16-bit raw value from bits 31--16. We shift // the bits above 31 down by 11 bits. unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; IGC_ASSERT((!Alignment || isPowerOf2_32(Alignment)) && "Alignment must be a power of two."); if (Alignment) B.addAlignmentAttr(Alignment); addRawAttributeValue(B, ((EncodedAttrs & (0xfffffULL << 32)) >> 11) | (EncodedAttrs & 0xffff)); } Error BitcodeReader::parseAttributeBlock() { if (Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID)) return error("Invalid record"); if (!MAttributes.empty()) return error("Invalid multiple blocks"); SmallVector Record; SmallVector Attrs; // Read all the records. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_CODE_ENTRY_OLD: // ENTRY: [paramidx0, attr0, ...] // FIXME: Remove in 4.0. if (Record.size() & 1) return error("Invalid record"); for (unsigned i = 0, e = Record.size(); i != e; i += 2) { AttrBuilder B; decodeLLVMAttributesForBitcode(B, Record[i+1]); Attrs.push_back(AttributeList::get(Context, Record[i], B)); } MAttributes.push_back(AttributeList::get(Context, Attrs)); Attrs.clear(); break; case bitc::PARAMATTR_CODE_ENTRY: // ENTRY: [attrgrp0, attrgrp1, ...] for (unsigned i = 0, e = Record.size(); i != e; ++i) Attrs.push_back(MAttributeGroups[Record[i]]); MAttributes.push_back(AttributeList::get(Context, Attrs)); Attrs.clear(); break; } } } // Returns Attribute::None on unrecognized codes. static Attribute::AttrKind getAttrFromCode(uint64_t Code) { switch (Code) { default: return Attribute::None; case bitc::ATTR_KIND_ALIGNMENT: return Attribute::Alignment; case bitc::ATTR_KIND_ALWAYS_INLINE: return Attribute::AlwaysInline; case bitc::ATTR_KIND_ARGMEMONLY: return Attribute::ArgMemOnly; case bitc::ATTR_KIND_BUILTIN: return Attribute::Builtin; case bitc::ATTR_KIND_BY_VAL: return Attribute::ByVal; case bitc::ATTR_KIND_IN_ALLOCA: return Attribute::InAlloca; case bitc::ATTR_KIND_COLD: return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: return Attribute::InaccessibleMemOnly; case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: return Attribute::InaccessibleMemOrArgMemOnly; case bitc::ATTR_KIND_INLINE_HINT: return Attribute::InlineHint; case bitc::ATTR_KIND_IN_REG: return Attribute::InReg; case bitc::ATTR_KIND_JUMP_TABLE: return Attribute::JumpTable; case bitc::ATTR_KIND_MIN_SIZE: return Attribute::MinSize; case bitc::ATTR_KIND_NAKED: return Attribute::Naked; case bitc::ATTR_KIND_NEST: return Attribute::Nest; case bitc::ATTR_KIND_NO_ALIAS: return Attribute::NoAlias; case bitc::ATTR_KIND_NO_BUILTIN: return Attribute::NoBuiltin; case bitc::ATTR_KIND_NO_CAPTURE: return Attribute::NoCapture; case bitc::ATTR_KIND_NO_DUPLICATE: return Attribute::NoDuplicate; case bitc::ATTR_KIND_NO_IMPLICIT_FLOAT: return Attribute::NoImplicitFloat; case bitc::ATTR_KIND_NO_INLINE: return Attribute::NoInline; case bitc::ATTR_KIND_NO_RECURSE: return Attribute::NoRecurse; case bitc::ATTR_KIND_NON_LAZY_BIND: return Attribute::NonLazyBind; case bitc::ATTR_KIND_NON_NULL: return Attribute::NonNull; case bitc::ATTR_KIND_DEREFERENCEABLE: return Attribute::Dereferenceable; case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: return Attribute::DereferenceableOrNull; case bitc::ATTR_KIND_ALLOC_SIZE: return Attribute::AllocSize; case bitc::ATTR_KIND_NO_RED_ZONE: return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: return Attribute::NoReturn; case bitc::ATTR_KIND_NOCF_CHECK: return Attribute::NoCfCheck; case bitc::ATTR_KIND_NO_UNWIND: return Attribute::NoUnwind; case bitc::ATTR_KIND_OPT_FOR_FUZZING: return Attribute::OptForFuzzing; case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: return Attribute::OptimizeForSize; case bitc::ATTR_KIND_OPTIMIZE_NONE: return Attribute::OptimizeNone; case bitc::ATTR_KIND_READ_NONE: return Attribute::ReadNone; case bitc::ATTR_KIND_READ_ONLY: return Attribute::ReadOnly; case bitc::ATTR_KIND_RETURNED: return Attribute::Returned; case bitc::ATTR_KIND_RETURNS_TWICE: return Attribute::ReturnsTwice; case bitc::ATTR_KIND_S_EXT: return Attribute::SExt; case bitc::ATTR_KIND_SPECULATABLE: return Attribute::Speculatable; case bitc::ATTR_KIND_STACK_ALIGNMENT: return Attribute::StackAlignment; case bitc::ATTR_KIND_STACK_PROTECT: return Attribute::StackProtect; case bitc::ATTR_KIND_STACK_PROTECT_REQ: return Attribute::StackProtectReq; case bitc::ATTR_KIND_STACK_PROTECT_STRONG: return Attribute::StackProtectStrong; case bitc::ATTR_KIND_SAFESTACK: return Attribute::SafeStack; case bitc::ATTR_KIND_SHADOWCALLSTACK: return Attribute::ShadowCallStack; case bitc::ATTR_KIND_STRICT_FP: return Attribute::StrictFP; case bitc::ATTR_KIND_STRUCT_RET: return Attribute::StructRet; case bitc::ATTR_KIND_SANITIZE_ADDRESS: return Attribute::SanitizeAddress; case bitc::ATTR_KIND_SANITIZE_HWADDRESS: return Attribute::SanitizeHWAddress; case bitc::ATTR_KIND_SANITIZE_THREAD: return Attribute::SanitizeThread; case bitc::ATTR_KIND_SANITIZE_MEMORY: return Attribute::SanitizeMemory; case bitc::ATTR_KIND_SPECULATIVE_LOAD_HARDENING: return Attribute::SpeculativeLoadHardening; case bitc::ATTR_KIND_SWIFT_ERROR: return Attribute::SwiftError; case bitc::ATTR_KIND_SWIFT_SELF: return Attribute::SwiftSelf; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; case bitc::ATTR_KIND_WRITEONLY: return Attribute::WriteOnly; case bitc::ATTR_KIND_Z_EXT: return Attribute::ZExt; } } Error BitcodeReader::parseAlignmentValue(uint64_t Exponent, unsigned &Alignment) { // Note: Alignment in bitcode files is incremented by 1, so that zero // can be used for default alignment. if (Exponent > Value::MaxAlignmentExponent + 1) return error("Invalid alignment value"); Alignment = (1 << static_cast(Exponent)) >> 1; return Error::success(); } Error BitcodeReader::parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind) { *Kind = getAttrFromCode(Code); if (*Kind == Attribute::None) return error("Unknown attribute kind (" + Twine(Code) + ")"); return Error::success(); } Error BitcodeReader::parseAttributeGroupBlock() { if (Stream.EnterSubBlock(bitc::PARAMATTR_GROUP_BLOCK_ID)) return error("Invalid record"); if (!MAttributeGroups.empty()) return error("Invalid multiple blocks"); SmallVector Record; // Read all the records. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_GRP_CODE_ENTRY: { // ENTRY: [grpid, idx, a0, a1, ...] if (Record.size() < 3) return error("Invalid record"); uint64_t GrpID = Record[0]; uint64_t Idx = Record[1]; // Index of the object this attribute refers to. AttrBuilder B; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Record[i] == 0) { // Enum attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; B.addAttribute(Kind); } else if (Record[i] == 1) { // Integer attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; if (Kind == Attribute::Alignment) B.addAlignmentAttr(Record[++i]); else if (Kind == Attribute::StackAlignment) B.addStackAlignmentAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); else if (Kind == Attribute::DereferenceableOrNull) B.addDereferenceableOrNullAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); } else { // String attribute IGC_ASSERT((Record[i] == 3 || Record[i] == 4) && "Invalid attribute group entry"); bool HasValue = (Record[i++] == 4); SmallString<64> KindStr; SmallString<64> ValStr; while (Record[i] != 0 && i != e) KindStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Kind string not null terminated"); if (HasValue) { // Has a value associated with it. ++i; // Skip the '0' that terminates the "kind" string. while (Record[i] != 0 && i != e) ValStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Value string not null terminated"); } B.addAttribute(KindStr.str(), ValStr.str()); } } MAttributeGroups[GrpID] = AttributeList::get(Context, Idx, B); break; } } } } Error BitcodeReader::parseTypeTable() { if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW)) return error("Invalid record"); return parseTypeTableBody(); } Error BitcodeReader::parseTypeTableBody() { if (!TypeList.empty()) return error("Invalid multiple blocks"); SmallVector Record; unsigned NumRecords = 0; SmallString<64> TypeName; // Read all the records for this type table. while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NumRecords != TypeList.size()) return error("Malformed block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *ResultTy = nullptr; switch (Stream.readRecord(Entry.ID, Record)) { default: return error("Invalid value"); case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] // TYPE_CODE_NUMENTRY contains a count of the number of types in the // type list. This allows us to reserve space. if (Record.size() < 1) return error("Invalid record"); TypeList.resize(Record[0]); continue; case bitc::TYPE_CODE_VOID: // VOID ResultTy = Type::getVoidTy(Context); break; case bitc::TYPE_CODE_HALF: // HALF ResultTy = Type::getHalfTy(Context); break; case bitc::TYPE_CODE_FLOAT: // FLOAT ResultTy = Type::getFloatTy(Context); break; case bitc::TYPE_CODE_DOUBLE: // DOUBLE ResultTy = Type::getDoubleTy(Context); break; case bitc::TYPE_CODE_X86_FP80: // X86_FP80 ResultTy = Type::getX86_FP80Ty(Context); break; case bitc::TYPE_CODE_FP128: // FP128 ResultTy = Type::getFP128Ty(Context); break; case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 ResultTy = Type::getPPC_FP128Ty(Context); break; case bitc::TYPE_CODE_LABEL: // LABEL ResultTy = Type::getLabelTy(Context); break; case bitc::TYPE_CODE_METADATA: // METADATA ResultTy = Type::getMetadataTy(Context); break; case bitc::TYPE_CODE_X86_MMX: // X86_MMX ResultTy = Type::getX86_MMXTy(Context); break; case bitc::TYPE_CODE_TOKEN: // TOKEN ResultTy = Type::getTokenTy(Context); break; case bitc::TYPE_CODE_INTEGER: { // INTEGER: [width] if (Record.size() < 1) return error("Invalid record"); uint64_t NumBits = Record[0]; if (NumBits < IntegerType::MIN_INT_BITS || NumBits > IntegerType::MAX_INT_BITS) return error("Bitwidth for integer type out of range"); ResultTy = IntegerType::get(Context, NumBits); break; } case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or // [pointee type, address space] if (Record.size() < 1) return error("Invalid record"); unsigned AddressSpace = 0; if (Record.size() == 2) AddressSpace = Record[1]; ResultTy = getTypeByID(Record[0]); if (!ResultTy || !PointerType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = PointerType::get(ResultTy, AddressSpace); break; } case bitc::TYPE_CODE_FUNCTION_OLD: { // FIXME: attrid is dead, remove it in LLVM 4.0 // FUNCTION: [vararg, attrid, retty, paramty x N] if (Record.size() < 3) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 3, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) ArgTys.push_back(T); else break; } ResultTy = getTypeByID(Record[2]); if (!ResultTy || ArgTys.size() < Record.size()-3) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_FUNCTION: { // FUNCTION: [vararg, retty, paramty x N] if (Record.size() < 2) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) { if (!FunctionType::isValidArgumentType(T)) return error("Invalid function argument type"); ArgTys.push_back(T); } else break; } ResultTy = getTypeByID(Record[1]); if (!ResultTy || ArgTys.size() < Record.size()-2) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid type"); ResultTy = StructType::get(Context, EltTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N] if (convertToString(Record, 0, TypeName)) return error("Invalid record"); continue; case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid record"); Res->setBody(EltTys, Record[0]); ResultTy = Res; break; } case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: [] if (Record.size() != 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct with no body. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); ResultTy = Res; break; } case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !ArrayType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = ArrayType::get(ResultTy, Record[0]); break; case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); if (Record[0] == 0) return error("Invalid vector length"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !StructType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = VectorType::get(ResultTy, Record[0]); break; } if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); if (TypeList[NumRecords]) return error( "Invalid TYPE table: Only named structs can be forward referenced"); IGC_ASSERT(ResultTy && "Didn't read a type?"); TypeList[NumRecords++] = ResultTy; } } Error BitcodeReader::parseOperandBundleTags() { if (Stream.EnterSubBlock(bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID)) return error("Invalid record"); if (!BundleTags.empty()) return error("Invalid multiple blocks"); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Tags are implicitly mapped to integers by their order. if (Stream.readRecord(Entry.ID, Record) != bitc::OPERAND_BUNDLE_TAG) return error("Invalid record"); // OPERAND_BUNDLE_TAG: [strchr x N] BundleTags.emplace_back(); if (convertToString(Record, 0, BundleTags.back())) return error("Invalid record"); Record.clear(); } } Error BitcodeReader::parseSyncScopeNames() { if (Stream.EnterSubBlock(bitc::SYNC_SCOPE_NAMES_BLOCK_ID)) return error("Invalid record"); if (!SSIDs.empty()) return error("Invalid multiple synchronization scope names blocks"); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (SSIDs.empty()) return error("Invalid empty synchronization scope names block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Synchronization scope names are implicitly mapped to synchronization // scope IDs by their order. if (Stream.readRecord(Entry.ID, Record) != bitc::SYNC_SCOPE_NAME) return error("Invalid record"); SmallString<16> SSN; if (convertToString(Record, 0, SSN)) return error("Invalid record"); SSIDs.push_back(Context.getOrInsertSyncScopeID(SSN)); Record.clear(); } } /// Associate a value with its name from the given index in the provided record. Expected BitcodeReader::recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT) { SmallString<128> ValueName; if (convertToString(Record, NameIndex, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; if (ValueID >= ValueList.size() || !ValueList[ValueID]) return error("Invalid record"); Value *V = ValueList[ValueID]; StringRef NameStr(ValueName.data(), ValueName.size()); if (NameStr.find_first_of(0) != StringRef::npos) return error("Invalid value name"); V->setName(NameStr); auto *GO = dyn_cast(V); if (GO) { if (GO->getComdat() == reinterpret_cast(1)) { if (TT.supportsCOMDAT()) GO->setComdat(TheModule->getOrInsertComdat(V->getName())); else GO->setComdat(nullptr); } } return V; } /// Helper to note and return the current location, and jump to the given /// offset. static uint64_t jumpToValueSymbolTable(uint64_t Offset, BitstreamCursor &Stream) { // Save the current parsing location so we can jump back at the end // of the VST read. uint64_t CurrentBit = Stream.GetCurrentBitNo(); Stream.JumpToBit(Offset * 32); #ifndef NDEBUG // Do some checking if we are in debug mode. BitstreamEntry Entry = Stream.advance(); IGC_ASSERT(Entry.Kind == BitstreamEntry::SubBlock); IGC_ASSERT(Entry.ID == bitc::VALUE_SYMTAB_BLOCK_ID); #else // In NDEBUG mode ignore the output so we don't get an unused variable // warning. Stream.advance(); #endif return CurrentBit; } void BitcodeReader::setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F, ArrayRef Record) { // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. uint64_t FuncWordOffset = Record[1] - 1; uint64_t FuncBitOffset = FuncWordOffset * 32; DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta; // Set the LastFunctionBlockBit to point to the last function block. // Later when parsing is resumed after function materialization, // we can simply skip that last function block. if (FuncBitOffset > LastFunctionBlockBit) LastFunctionBlockBit = FuncBitOffset; } /// Read a new-style GlobalValue symbol table. Error BitcodeReader::parseGlobalValueSymbolTable() { unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: break; } Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { case bitc::VST_CODE_FNENTRY: // [valueid, offset] setDeferredFunctionInfo(FuncBitcodeOffsetDelta, cast(ValueList[Record[0]]), Record); break; } } } /// Parse the value symbol table at either the current parsing location or /// at the given bit offset if provided. Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) { uint64_t CurrentBit; // Pass in the Offset to distinguish between calling for the module-level // VST (where we want to jump to the VST offset) and the function-level // VST (where we don't). if (Offset > 0) { CurrentBit = jumpToValueSymbolTable(Offset, Stream); // If this module uses a string table, read this as a module-level VST. if (UseStrtab) { if (Error Err = parseGlobalValueSymbolTable()) return Err; Stream.JumpToBit(CurrentBit); return Error::success(); } // Otherwise, the VST will be in a similar format to a function-level VST, // and will contain symbol names. } // Compute the delta between the bitcode indices in the VST (the word offset // to the word-aligned ENTER_SUBBLOCK for the function block, and that // expected by the lazy reader. The reader's EnterSubBlock expects to have // already read the ENTER_SUBBLOCK code (size getAbbrevIDWidth) and BlockID // (size BlockIDWidth). Note that we access the stream's AbbrevID width here // just before entering the VST subblock because: 1) the EnterSubBlock // changes the AbbrevID width; 2) the VST block is nested within the same // outer MODULE_BLOCK as the FUNCTION_BLOCKs and therefore have the same // AbbrevID width before calling EnterSubBlock; and 3) when we want to // jump to the FUNCTION_BLOCK using this offset later, we don't want // to rely on the stream's AbbrevID width being that of the MODULE_BLOCK. unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; Triple TT(TheModule->getTargetTriple()); // Read all the records for this value table. SmallString<128> ValueName; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (Offset > 0) Stream.JumpToBit(CurrentBit); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: unknown type. break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] Expected ValOrErr = recordValue(Record, 1, TT); if (Error Err = ValOrErr.takeError()) return Err; ValOrErr.get(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] Expected ValOrErr = recordValue(Record, 2, TT); if (Error Err = ValOrErr.takeError()) return Err; Value *V = ValOrErr.get(); // Ignore function offsets emitted for aliases of functions in older // versions of LLVM. if (auto *F = dyn_cast(V)) setDeferredFunctionInfo(FuncBitcodeOffsetDelta, F, Record); break; } case bitc::VST_CODE_BBENTRY: { if (convertToString(Record, 1, ValueName)) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[0]); if (!BB) return error("Invalid record"); BB->setName(StringRef(ValueName.data(), ValueName.size())); ValueName.clear(); break; } } } } /// Decode a signed value stored with the sign bit in the LSB for dense VBR /// encoding. uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) { if ((V & 1) == 0) return V >> 1; if (V != 1) return -(V >> 1); // There is no such thing as -0 with integers. "-0" really means MININT. return 1ULL << 63; } /// Resolve all of the initializers for global values and aliases that we can. Error BitcodeReader::resolveGlobalAndIndirectSymbolInits() { std::vector> GlobalInitWorklist; std::vector> IndirectSymbolInitWorklist; std::vector> FunctionPrefixWorklist; std::vector> FunctionPrologueWorklist; std::vector> FunctionPersonalityFnWorklist; GlobalInitWorklist.swap(GlobalInits); IndirectSymbolInitWorklist.swap(IndirectSymbolInits); FunctionPrefixWorklist.swap(FunctionPrefixes); FunctionPrologueWorklist.swap(FunctionPrologues); FunctionPersonalityFnWorklist.swap(FunctionPersonalityFns); while (!GlobalInitWorklist.empty()) { unsigned ValID = GlobalInitWorklist.back().second; if (ValID >= ValueList.size()) { // Not ready to resolve this yet, it requires something later in the file. GlobalInits.push_back(GlobalInitWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) GlobalInitWorklist.back().first->setInitializer(C); else return error("Expected a constant"); } GlobalInitWorklist.pop_back(); } while (!IndirectSymbolInitWorklist.empty()) { unsigned ValID = IndirectSymbolInitWorklist.back().second; if (ValID >= ValueList.size()) { IndirectSymbolInits.push_back(IndirectSymbolInitWorklist.back()); } else { Constant *C = dyn_cast_or_null(ValueList[ValID]); if (!C) return error("Expected a constant"); GlobalIndirectSymbol *GIS = IndirectSymbolInitWorklist.back().first; if (isa(GIS) && C->getType() != GIS->getType()) return error("Alias and aliasee types don't match"); GIS->setIndirectSymbol(C); } IndirectSymbolInitWorklist.pop_back(); } while (!FunctionPrefixWorklist.empty()) { unsigned ValID = FunctionPrefixWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrefixes.push_back(FunctionPrefixWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrefixWorklist.back().first->setPrefixData(C); else return error("Expected a constant"); } FunctionPrefixWorklist.pop_back(); } while (!FunctionPrologueWorklist.empty()) { unsigned ValID = FunctionPrologueWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrologues.push_back(FunctionPrologueWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrologueWorklist.back().first->setPrologueData(C); else return error("Expected a constant"); } FunctionPrologueWorklist.pop_back(); } while (!FunctionPersonalityFnWorklist.empty()) { unsigned ValID = FunctionPersonalityFnWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPersonalityFns.push_back(FunctionPersonalityFnWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPersonalityFnWorklist.back().first->setPersonalityFn(C); else return error("Expected a constant"); } FunctionPersonalityFnWorklist.pop_back(); } return Error::success(); } static APInt readWideAPInt(ArrayRef Vals, unsigned TypeBits) { SmallVector Words(Vals.size()); transform(Vals, Words.begin(), BitcodeReader::decodeSignRotatedValue); return APInt(TypeBits, Words); } Error BitcodeReader::parseConstants() { if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this value table. Type *CurTy = Type::getInt32Ty(Context); unsigned NextCstNo = ValueList.size(); while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NextCstNo != ValueList.size()) return error("Invalid constant reference"); // Once all the constants have been read, go through and resolve forward // references. ValueList.resolveConstantForwardRefs(); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *VoidType = Type::getVoidTy(Context); Value *V = nullptr; unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: unknown constant case bitc::CST_CODE_UNDEF: // UNDEF V = UndefValue::get(CurTy); break; case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid] if (Record.empty()) return error("Invalid record"); if (Record[0] >= TypeList.size() || !TypeList[Record[0]]) return error("Invalid record"); if (TypeList[Record[0]] == VoidType) return error("Invalid constant type"); CurTy = TypeList[Record[0]]; continue; // Skip the ValueList manipulation. case bitc::CST_CODE_NULL: // NULL V = Constant::getNullValue(CurTy); break; case bitc::CST_CODE_INTEGER: // INTEGER: [intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0])); break; case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); APInt VInt = readWideAPInt(Record, cast(CurTy)->getBitWidth()); V = ConstantInt::get(Context, VInt); break; } case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval] if (Record.empty()) return error("Invalid record"); if (CurTy->isHalfTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf(), APInt(16, (uint16_t)Record[0]))); else if (CurTy->isFloatTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle(), APInt(32, (uint32_t)Record[0]))); else if (CurTy->isDoubleTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble(), APInt(64, Record[0]))); else if (CurTy->isX86_FP80Ty()) { // Bits are not stored the same way as a normal i80 APInt, compensate. uint64_t Rearrange[2]; Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16); Rearrange[1] = Record[0] >> 48; V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended(), APInt(80, Rearrange))); } else if (CurTy->isFP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad(), APInt(128, Record))); else if (CurTy->isPPC_FP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble(), APInt(128, Record))); else V = UndefValue::get(CurTy); break; } case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number] if (Record.empty()) return error("Invalid record"); unsigned Size = Record.size(); SmallVector Elts; if (StructType *STy = dyn_cast(CurTy)) { for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); } else if (ArrayType *ATy = dyn_cast(CurTy)) { Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantArray::get(ATy, Elts); } else if (VectorType *VTy = dyn_cast(CurTy)) { Type *EltTy = VTy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantVector::get(Elts); } else { V = UndefValue::get(CurTy); } break; } case bitc::CST_CODE_STRING: // STRING: [values] case bitc::CST_CODE_CSTRING: { // CSTRING: [values] if (Record.empty()) return error("Invalid record"); SmallString<16> Elts(Record.begin(), Record.end()); V = ConstantDataArray::getString(Context, Elts, BitCode == bitc::CST_CODE_CSTRING); break; } case bitc::CST_CODE_DATA: {// DATA: [n x value] if (Record.empty()) return error("Invalid record"); Type *EltTy = cast(CurTy)->getElementType(); if (EltTy->isIntegerTy(8)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(16)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(32)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(64)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isHalfTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isFloatTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isDoubleTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else { return error("Invalid type for value"); } break; } case bitc::CST_CODE_CE_UNOP: { // CE_UNOP: [opcode, opval] if (Record.size() < 2) return error("Invalid record"); int Opc = getDecodedUnaryOpcode(Record[0], CurTy); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown unop. } else { Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); unsigned Flags = 0; V = ConstantExpr::get(Opc, LHS, Flags); } break; } case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[0], CurTy); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown binop. } else { Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy); unsigned Flags = 0; if (Record.size() >= 4) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoSignedWrap; if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoUnsignedWrap; } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[3] & (1 << bitc::PEO_EXACT)) Flags |= SDivOperator::IsExact; } } V = ConstantExpr::get(Opc, LHS, RHS, Flags); } break; } case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedCastOpcode(Record[0]); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown cast. } else { Type *OpTy = getTypeByID(Record[1]); if (!OpTy) return error("Invalid record"); Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy); V = upgradeBitCastExpr(Opc, Op, CurTy); if (!V) V = ConstantExpr::getCast(Opc, Op, CurTy); } break; } case bitc::CST_CODE_CE_INBOUNDS_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX: { // [ty, flags, n x // operands] unsigned OpNum = 0; Type *PointeeType = nullptr; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX || Record.size() % 2) PointeeType = getTypeByID(Record[OpNum++]); bool InBounds = false; Optional InRangeIndex; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX) { uint64_t Op = Record[OpNum++]; InBounds = Op & 1; InRangeIndex = Op >> 1; } else if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP) InBounds = true; SmallVector Elts; while (OpNum != Record.size()) { Type *ElTy = getTypeByID(Record[OpNum++]); if (!ElTy) return error("Invalid record"); Elts.push_back(ValueList.getConstantFwdRef(Record[OpNum++], ElTy)); } if (PointeeType && PointeeType != cast(Elts[0]->getType()->getScalarType()) ->getElementType()) return error("Explicit gep operator type does not match pointee type " "of pointer operand"); if (Elts.size() < 1) return error("Invalid gep with no operands"); ArrayRef Indices(Elts.begin() + 1, Elts.end()); V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices, InBounds, InRangeIndex); break; } case bitc::CST_CODE_CE_SELECT: { // CE_SELECT: [opval#, opval#, opval#] if (Record.size() < 3) return error("Invalid record"); Type *SelectorTy = Type::getInt1Ty(Context); // The selector might be an i1 or an // Get the type from the ValueList before getting a forward ref. if (VectorType *VTy = dyn_cast(CurTy)) if (Value *V = ValueList[Record[0]]) if (SelectorTy != V->getType()) SelectorTy = VectorType::get(SelectorTy, VTy->getNumElements()); V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0], SelectorTy), ValueList.getConstantFwdRef(Record[1],CurTy), ValueList.getConstantFwdRef(Record[2],CurTy)); break; } case bitc::CST_CODE_CE_EXTRACTELT : { // CE_EXTRACTELT: [opty, opval, opty, opval] if (Record.size() < 3) return error("Invalid record"); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op1 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op1) return error("Invalid record"); V = ConstantExpr::getExtractElement(Op0, Op1); break; } case bitc::CST_CODE_CE_INSERTELT : { // CE_INSERTELT: [opval, opval, opty, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy->getElementType()); Constant *Op2 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op2 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op2) return error("Invalid record"); V = ConstantExpr::getInsertElement(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), OpTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval] VectorType *RTy = dyn_cast(CurTy); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (Record.size() < 4 || !RTy || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), RTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred] if (Record.size() < 4) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); if (OpTy->isFPOrFPVectorTy()) V = ConstantExpr::getFCmp(Record[3], Op0, Op1); else V = ConstantExpr::getICmp(Record[3], Op0, Op1); break; } // This maintains backward compatibility, pre-asm dialect keywords. // FIXME: Remove with the 4.0 release. case bitc::CST_CODE_INLINEASM_OLD: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = Record[0] >> 1; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; PointerType *PTy = cast(CurTy); UpgradeInlineAsmString(&AsmStr); V = InlineAsm::get(cast(PTy->getElementType()), AsmStr, ConstrStr, HasSideEffects, IsAlignStack); break; } // This version adds support for the asm dialect keywords (e.g., // inteldialect). case bitc::CST_CODE_INLINEASM: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = (Record[0] >> 1) & 1; unsigned AsmDialect = Record[0] >> 2; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; PointerType *PTy = cast(CurTy); UpgradeInlineAsmString(&AsmStr); V = InlineAsm::get(cast(PTy->getElementType()), AsmStr, ConstrStr, HasSideEffects, IsAlignStack, InlineAsm::AsmDialect(AsmDialect)); break; } case bitc::CST_CODE_BLOCKADDRESS:{ if (Record.size() < 3) return error("Invalid record"); Type *FnTy = getTypeByID(Record[0]); if (!FnTy) return error("Invalid record"); Function *Fn = dyn_cast_or_null(ValueList.getConstantFwdRef(Record[1],FnTy)); if (!Fn) return error("Invalid record"); // If the function is already parsed we can insert the block address right // away. BasicBlock *BB; unsigned BBID = Record[2]; if (!BBID) // Invalid reference to entry block. return error("Invalid ID"); if (!Fn->empty()) { Function::iterator BBI = Fn->begin(), BBE = Fn->end(); for (size_t I = 0, E = BBID; I != E; ++I) { if (BBI == BBE) return error("Invalid ID"); ++BBI; } BB = &*BBI; } else { // Otherwise insert a placeholder and remember it so it can be inserted // when the function is parsed. auto &FwdBBs = BasicBlockFwdRefs[Fn]; if (FwdBBs.empty()) BasicBlockFwdRefQueue.push_back(Fn); if (FwdBBs.size() < BBID + 1) FwdBBs.resize(BBID + 1); if (!FwdBBs[BBID]) FwdBBs[BBID] = BasicBlock::Create(Context); BB = FwdBBs[BBID]; } V = BlockAddress::get(Fn, BB); break; } } ValueList.assignValue(V, NextCstNo); ++NextCstNo; } } Error BitcodeReader::parseUseLists() { if (Stream.EnterSubBlock(bitc::USELIST_BLOCK_ID)) return error("Invalid record"); // Read all the records. SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a use list record. Record.clear(); bool IsBB = false; switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: unknown type. break; case bitc::USELIST_CODE_BB: IsBB = true; LLVM_FALLTHROUGH; case bitc::USELIST_CODE_DEFAULT: { unsigned RecordLength = Record.size(); if (RecordLength < 3) // Records should have at least an ID and two indexes. return error("Invalid record"); unsigned ID = Record.back(); Record.pop_back(); Value *V; if (IsBB) { IGC_ASSERT(ID < FunctionBBs.size() && "Basic block not found"); V = FunctionBBs[ID]; } else V = ValueList[ID]; unsigned NumUses = 0; SmallDenseMap Order; for (const Use &U : V->materialized_uses()) { if (++NumUses > Record.size()) break; Order[&U] = Record[NumUses - 1]; } if (Order.size() != Record.size() || NumUses > Record.size()) // Mismatches can happen if the functions are being materialized lazily // (out-of-order), or a value has been upgraded. break; V->sortUseList([&](const Use &L, const Use &R) { return Order.lookup(&L) < Order.lookup(&R); }); break; } } } } /// When we see the block for metadata, remember where it is and then skip it. /// This lets us lazily deserialize the metadata. Error BitcodeReader::rememberAndSkipMetadata() { // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); DeferredMetadataInfo.push_back(CurBit); // Skip over the block for now. if (Stream.SkipBlock()) return error("Invalid record"); return Error::success(); } Error BitcodeReader::materializeMetadata() { for (uint64_t BitPos : DeferredMetadataInfo) { // Move the bit stream to the saved position. Stream.JumpToBit(BitPos); if (Error Err = MDLoader->parseModuleMetadata()) return Err; } // Upgrade "Linker Options" module flag to "llvm.linker.options" module-level // metadata. if (Metadata *Val = TheModule->getModuleFlag("Linker Options")) { NamedMDNode *LinkerOpts = TheModule->getOrInsertNamedMetadata("llvm.linker.options"); for (const MDOperand &MDOptions : cast(Val)->operands()) LinkerOpts->addOperand(cast(MDOptions)); } DeferredMetadataInfo.clear(); return Error::success(); } void BitcodeReader::setStripDebugInfo() { StripDebugInfo = true; } /// When we see the block for a function body, remember where it is and then /// skip it. This lets us lazily deserialize the functions. Error BitcodeReader::rememberAndSkipFunctionBody() { // Get the function we are talking about. if (FunctionsWithBodies.empty()) return error("Insufficient function protos"); Function *Fn = FunctionsWithBodies.back(); FunctionsWithBodies.pop_back(); // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); IGC_ASSERT( (DeferredFunctionInfo[Fn] == 0 || DeferredFunctionInfo[Fn] == CurBit) && "Mismatch between VST and scanned function offsets"); DeferredFunctionInfo[Fn] = CurBit; // Skip over the function block for now. if (Stream.SkipBlock()) return error("Invalid record"); return Error::success(); } Error BitcodeReader::globalCleanup() { // Patch the initializers for globals and aliases up. if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; if (!GlobalInits.empty() || !IndirectSymbolInits.empty()) return error("Malformed global initializer set"); // Look for intrinsic functions which need to be upgraded at some point for (Function &F : *TheModule) { //LLVM_UPGRADE_TODO //check this funciton upgradeDebugIntrinsics (in llvm 4.0 not present) //MDLoader->upgradeDebugIntrinsics(F); Function *NewFn; if (UpgradeIntrinsicFunction(&F, NewFn)) UpgradedIntrinsics[&F] = NewFn; else if (auto Remangled = Intrinsic::remangleIntrinsicFunction(&F)) // Some types could be renamed during loading if several modules are // loaded in the same LLVMContext (LTO scenario). In this case we should // remangle intrinsics names as well. RemangledIntrinsics[&F] = Remangled.getValue(); } // Look for global variables which need to be renamed. for (GlobalVariable &GV : TheModule->globals()) UpgradeGlobalVariable(&GV); // Force deallocation of memory for these vectors to favor the client that // want lazy deserialization. std::vector>().swap(GlobalInits); std::vector>().swap( IndirectSymbolInits); return Error::success(); } /// Support for lazy parsing of function bodies. This is required if we /// either have an old bitcode file without a VST forward declaration record, /// or if we have an anonymous function being materialized, since anonymous /// functions do not have a name and are therefore not in the VST. Error BitcodeReader::rememberAndSkipFunctionBodies() { Stream.JumpToBit(NextUnreadBit); if (Stream.AtEndOfStream()) return error("Could not find function in stream"); if (!SeenFirstFunctionBody) return error("Trying to materialize functions before seeing function blocks"); // An old bitcode file with the symbol table at the end would have // finished the parse greedily. IGC_ASSERT(SeenValueSymbolTable); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { default: return error("Expect SubBlock"); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: return error("Expect function block"); case bitc::FUNCTION_BLOCK_ID: if (Error Err = rememberAndSkipFunctionBody()) return Err; NextUnreadBit = Stream.GetCurrentBitNo(); return Error::success(); } } } } bool BitcodeReaderBase::readBlockInfo() { Optional NewBlockInfo = Stream.ReadBlockInfoBlock(); if (!NewBlockInfo) return true; BlockInfo = std::move(*NewBlockInfo); return false; } Error BitcodeReader::parseComdatRecord(ArrayRef Record) { // v1: [selection_kind, name] // v2: [strtab_offset, strtab_size, selection_kind] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.empty()) return error("Invalid record"); Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]); std::string OldFormatName; if (!UseStrtab) { if (Record.size() < 2) return error("Invalid record"); unsigned ComdatNameSize = Record[1]; OldFormatName.reserve(ComdatNameSize); for (unsigned i = 0; i != ComdatNameSize; ++i) OldFormatName += (char)Record[2 + i]; Name = OldFormatName; } Comdat *C = TheModule->getOrInsertComdat(Name); C->setSelectionKind(SK); ComdatList.push_back(C); return Error::success(); } static void inferDSOLocal(GlobalValue *GV) { // infer dso_local from linkage and visibility if it is not encoded. if (GV->hasLocalLinkage() || (!GV->hasDefaultVisibility() && !GV->hasExternalWeakLinkage())) GV->setDSOLocal(true); } Error BitcodeReader::parseGlobalVarRecord(ArrayRef Record) { // v1: [pointer type, isconst, initid, linkage, alignment, section, // visibility, threadlocal, unnamed_addr, externally_initialized, // dllstorageclass, comdat, attributes, preemption specifier] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.size() < 6) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); bool isConstant = Record[1] & 1; bool explicitType = Record[1] & 2; unsigned AddressSpace; if (explicitType) { AddressSpace = Record[1] >> 2; } else { if (!Ty->isPointerTy()) return error("Invalid type for value"); AddressSpace = cast(Ty)->getAddressSpace(); Ty = cast(Ty)->getElementType(); } uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); unsigned Alignment; if (Error Err = parseAlignmentValue(Record[4], Alignment)) return Err; std::string Section; if (Record[5]) { if (Record[5] - 1 >= SectionTable.size()) return error("Invalid ID"); Section = SectionTable[Record[5] - 1]; } GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; // Local linkage must have default visibility. if (Record.size() > 6 && !GlobalValue::isLocalLinkage(Linkage)) // FIXME: Change to an error if non-default in 4.0. Visibility = getDecodedVisibility(Record[6]); GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; if (Record.size() > 7) TLM = getDecodedThreadLocalMode(Record[7]); GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 8) UnnamedAddr = getDecodedUnnamedAddrType(Record[8]); bool ExternallyInitialized = false; if (Record.size() > 9) ExternallyInitialized = Record[9]; GlobalVariable *NewGV = new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, Name, nullptr, TLM, AddressSpace, ExternallyInitialized); NewGV->setAlignment(Alignment); if (!Section.empty()) NewGV->setSection(Section); NewGV->setVisibility(Visibility); NewGV->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10) NewGV->setDLLStorageClass(getDecodedDLLStorageClass(Record[10])); else upgradeDLLImportExportLinkage(NewGV, RawLinkage); ValueList.push_back(NewGV); // Remember which value to use for the global initializer. if (unsigned InitID = Record[2]) GlobalInits.push_back(std::make_pair(NewGV, InitID - 1)); if (Record.size() > 11) { if (unsigned ComdatID = Record[11]) { if (ComdatID > ComdatList.size()) return error("Invalid global variable comdat ID"); NewGV->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { NewGV->setComdat(reinterpret_cast(1)); } if (Record.size() > 12) { auto AS = getAttributes(Record[12]).getFnAttributes(); NewGV->setAttributes(AS); } if (Record.size() > 13) { NewGV->setDSOLocal(getDecodedDSOLocal(Record[13])); } inferDSOLocal(NewGV); return Error::success(); } Error BitcodeReader::parseFunctionRecord(ArrayRef Record) { // v1: [type, callingconv, isproto, linkage, paramattr, alignment, section, // visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat, // prefixdata, personalityfn, preemption specifier, addrspace] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.size() < 8) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); if (auto *PTy = dyn_cast(Ty)) Ty = PTy->getElementType(); auto *FTy = dyn_cast(Ty); if (!FTy) return error("Invalid type for value"); auto CC = static_cast(Record[1]); if (CC & ~CallingConv::MaxID) return error("Invalid calling convention ID"); unsigned AddrSpace = TheModule->getDataLayout().getProgramAddressSpace(); if (Record.size() > 16) AddrSpace = Record[16]; Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage, AddrSpace, Name, TheModule); Func->setCallingConv(CC); bool isProto = Record[2]; uint64_t RawLinkage = Record[3]; Func->setLinkage(getDecodedLinkage(RawLinkage)); Func->setAttributes(getAttributes(Record[4])); unsigned Alignment; if (Error Err = parseAlignmentValue(Record[5], Alignment)) return Err; Func->setAlignment(Alignment); if (Record[6]) { if (Record[6] - 1 >= SectionTable.size()) return error("Invalid ID"); Func->setSection(SectionTable[Record[6] - 1]); } // Local linkage must have default visibility. if (!Func->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. Func->setVisibility(getDecodedVisibility(Record[7])); if (Record.size() > 8 && Record[8]) { if (Record[8] - 1 >= GCTable.size()) return error("Invalid ID"); Func->setGC(GCTable[Record[8] - 1]); } GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 9) UnnamedAddr = getDecodedUnnamedAddrType(Record[9]); Func->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10 && Record[10] != 0) FunctionPrologues.push_back(std::make_pair(Func, Record[10] - 1)); if (Record.size() > 11) Func->setDLLStorageClass(getDecodedDLLStorageClass(Record[11])); else upgradeDLLImportExportLinkage(Func, RawLinkage); if (Record.size() > 12) { if (unsigned ComdatID = Record[12]) { if (ComdatID > ComdatList.size()) return error("Invalid function comdat ID"); Func->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { Func->setComdat(reinterpret_cast(1)); } if (Record.size() > 13 && Record[13] != 0) FunctionPrefixes.push_back(std::make_pair(Func, Record[13] - 1)); if (Record.size() > 14 && Record[14] != 0) FunctionPersonalityFns.push_back(std::make_pair(Func, Record[14] - 1)); if (Record.size() > 15) { Func->setDSOLocal(getDecodedDSOLocal(Record[15])); } inferDSOLocal(Func); ValueList.push_back(Func); // If this is a function with a body, remember the prototype we are // creating now, so that we can match up the body with them later. if (!isProto) { Func->setIsMaterializable(true); FunctionsWithBodies.push_back(Func); DeferredFunctionInfo[Func] = 0; } return Error::success(); } Error BitcodeReader::parseGlobalIndirectSymbolRecord( unsigned BitCode, ArrayRef Record) { // v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST) // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, // dllstorageclass, threadlocal, unnamed_addr, // preemption specifier] (name in VST) // v1 IFUNC: [alias type, addrspace, aliasee val#, linkage, // visibility, dllstorageclass, threadlocal, unnamed_addr, // preemption specifier] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD; if (Record.size() < (3 + (unsigned)NewRecord)) return error("Invalid record"); unsigned OpNum = 0; Type *Ty = getTypeByID(Record[OpNum++]); if (!Ty) return error("Invalid record"); unsigned AddrSpace; if (!NewRecord) { auto *PTy = dyn_cast(Ty); if (!PTy) return error("Invalid type for value"); Ty = PTy->getElementType(); AddrSpace = PTy->getAddressSpace(); } else { AddrSpace = Record[OpNum++]; } auto Val = Record[OpNum++]; auto Linkage = Record[OpNum++]; GlobalIndirectSymbol *NewGA; if (BitCode == bitc::MODULE_CODE_ALIAS || BitCode == bitc::MODULE_CODE_ALIAS_OLD) NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name, TheModule); else NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name, nullptr, TheModule); // Old bitcode files didn't have visibility field. // Local linkage must have default visibility. if (OpNum != Record.size()) { auto VisInd = OpNum++; if (!NewGA->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. NewGA->setVisibility(getDecodedVisibility(Record[VisInd])); } if (BitCode == bitc::MODULE_CODE_ALIAS || BitCode == bitc::MODULE_CODE_ALIAS_OLD) { if (OpNum != Record.size()) NewGA->setDLLStorageClass(getDecodedDLLStorageClass(Record[OpNum++])); else upgradeDLLImportExportLinkage(NewGA, Linkage); if (OpNum != Record.size()) NewGA->setThreadLocalMode(getDecodedThreadLocalMode(Record[OpNum++])); if (OpNum != Record.size()) NewGA->setUnnamedAddr(getDecodedUnnamedAddrType(Record[OpNum++])); } if (OpNum != Record.size()) NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++])); inferDSOLocal(NewGA); ValueList.push_back(NewGA); IndirectSymbolInits.push_back(std::make_pair(NewGA, Val)); return Error::success(); } Error BitcodeReader::parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata) { if (ResumeBit) Stream.JumpToBit(ResumeBit); else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this module. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return globalCleanup(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::BLOCKINFO_BLOCK_ID: if (readBlockInfo()) return error("Malformed block"); break; case bitc::PARAMATTR_BLOCK_ID: if (Error Err = parseAttributeBlock()) return Err; break; case bitc::PARAMATTR_GROUP_BLOCK_ID: if (Error Err = parseAttributeGroupBlock()) return Err; break; case bitc::TYPE_BLOCK_ID_NEW: if (Error Err = parseTypeTable()) return Err; break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (!SeenValueSymbolTable) { // Either this is an old form VST without function index and an // associated VST forward declaration record (which would have caused // the VST to be jumped to and parsed before it was encountered // normally in the stream), or there were no function blocks to // trigger an earlier parsing of the VST. IGC_ASSERT(VSTOffset == 0 || FunctionsWithBodies.empty()); if (Error Err = parseValueSymbolTable()) return Err; SeenValueSymbolTable = true; } else { // We must have had a VST forward declaration record, which caused // the parser to jump to and parse the VST earlier. IGC_ASSERT(VSTOffset > 0); if (Stream.SkipBlock()) return error("Invalid record"); } break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; break; case bitc::METADATA_BLOCK_ID: if (ShouldLazyLoadMetadata) { if (Error Err = rememberAndSkipMetadata()) return Err; break; } IGC_ASSERT(DeferredMetadataInfo.empty() && "Unexpected deferred metadata"); if (Error Err = MDLoader->parseModuleMetadata()) return Err; break; case bitc::METADATA_KIND_BLOCK_ID: if (Error Err = MDLoader->parseMetadataKinds()) return Err; break; case bitc::FUNCTION_BLOCK_ID: // If this is the first function body we've seen, reverse the // FunctionsWithBodies list. if (!SeenFirstFunctionBody) { std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end()); if (Error Err = globalCleanup()) return Err; SeenFirstFunctionBody = true; } if (VSTOffset > 0) { // If we have a VST forward declaration record, make sure we // parse the VST now if we haven't already. It is needed to // set up the DeferredFunctionInfo vector for lazy reading. if (!SeenValueSymbolTable) { if (Error Err = BitcodeReader::parseValueSymbolTable(VSTOffset)) return Err; SeenValueSymbolTable = true; // Fall through so that we record the NextUnreadBit below. // This is necessary in case we have an anonymous function that // is later materialized. Since it will not have a VST entry we // need to fall back to the lazy parse to find its offset. } else { // If we have a VST forward declaration record, but have already // parsed the VST (just above, when the first function body was // encountered here), then we are resuming the parse after // materializing functions. The ResumeBit points to the // start of the last function block recorded in the // DeferredFunctionInfo map. Skip it. if (Stream.SkipBlock()) return error("Invalid record"); continue; } } // Support older bitcode files that did not have the function // index in the VST, nor a VST forward declaration record, as // well as anonymous functions that do not have VST entries. // Build the DeferredFunctionInfo vector on the fly. if (Error Err = rememberAndSkipFunctionBody()) return Err; // Suspend parsing when we reach the function bodies. Subsequent // materialization calls will resume it when necessary. If the bitcode // file is old, the symbol table will be at the end instead and will not // have been seen yet. In this case, just finish the parse now. if (SeenValueSymbolTable) { NextUnreadBit = Stream.GetCurrentBitNo(); // After the VST has been parsed, we need to make sure intrinsic name // are auto-upgraded. return globalCleanup(); } break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: if (Error Err = parseOperandBundleTags()) return Err; break; case bitc::SYNC_SCOPE_NAMES_BLOCK_ID: if (Error Err = parseSyncScopeNames()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { Expected VersionOrErr = parseVersionRecord(Record); if (!VersionOrErr) return VersionOrErr.takeError(); UseRelativeIDs = *VersionOrErr >= 1; break; } case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setTargetTriple(S); break; } case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); size_t index = S.find("-a64:64:64"); if (index != std::string::npos) S.replace(index, 10, ""); TheModule->setDataLayout(S); break; } case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setModuleInlineAsm(S); break; } case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N] // FIXME: Remove in 4.0. std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Ignore value. break; } case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); SectionTable.push_back(S); break; } case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); GCTable.push_back(S); break; } case bitc::MODULE_CODE_COMDAT: if (Error Err = parseComdatRecord(Record)) return Err; break; case bitc::MODULE_CODE_GLOBALVAR: if (Error Err = parseGlobalVarRecord(Record)) return Err; break; case bitc::MODULE_CODE_FUNCTION: if (Error Err = parseFunctionRecord(Record)) return Err; break; case bitc::MODULE_CODE_IFUNC: case bitc::MODULE_CODE_ALIAS: case bitc::MODULE_CODE_ALIAS_OLD: if (Error Err = parseGlobalIndirectSymbolRecord(BitCode, Record)) return Err; break; /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); TheModule->setSourceFileName(ValueName); break; } Record.clear(); } } Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata, bool IsImporting) { TheModule = M; MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting, [&](unsigned ID) { return getTypeByID(ID); }); return parseModule(0, ShouldLazyLoadMetadata); } Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) { if (!isa(PtrType)) return error("Load/Store operand is not a pointer type"); Type *ElemType = cast(PtrType)->getElementType(); if (ValType && ValType != ElemType) return error("Explicit load/store type does not match pointee " "type of pointer operand"); if (!PointerType::isLoadableOrStorableType(ElemType)) return error("Cannot load/store from pointer"); return Error::success(); } /// Lazily parse the specified function body block. Error BitcodeReader::parseFunctionBody(Function *F) { if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID)) return error("Invalid record"); // Unexpected unresolved metadata when parsing function. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: incoming forward references"); InstructionList.clear(); unsigned ModuleValueListSize = ValueList.size(); unsigned ModuleMDLoaderSize = MDLoader->size(); // Add all the function arguments to the value table. for (Argument &I : F->args()) ValueList.push_back(&I); unsigned NextValueNo = ValueList.size(); BasicBlock *CurBB = nullptr; unsigned CurBBNo = 0; DebugLoc LastLoc; auto getLastInstruction = [&]() -> Instruction * { if (CurBB && !CurBB->empty()) return &CurBB->back(); else if (CurBBNo && FunctionBBs[CurBBNo - 1] && !FunctionBBs[CurBBNo - 1]->empty()) return &FunctionBBs[CurBBNo - 1]->back(); return nullptr; }; std::vector OperandBundles; // Read all the records. SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: goto OutOfRecordLoop; case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; NextValueNo = ValueList.size(); break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (Error Err = parseValueSymbolTable()) return Err; break; case bitc::METADATA_ATTACHMENT_ID: if (Error Err = MDLoader->parseMetadataAttachment(*F, InstructionList)) return Err; break; case bitc::METADATA_BLOCK_ID: IGC_ASSERT(DeferredMetadataInfo.empty() && "Must read all module-level metadata before function-level"); if (Error Err = MDLoader->parseFunctionMetadata()) return Err; break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Instruction *I = nullptr; unsigned BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: reject return error("Invalid value"); case bitc::FUNC_CODE_DECLAREBLOCKS: { // DECLAREBLOCKS: [nblocks] if (Record.size() < 1 || Record[0] == 0) return error("Invalid record"); // Create all the basic blocks for the function. FunctionBBs.resize(Record[0]); // See if anything took the address of blocks in this function. auto BBFRI = BasicBlockFwdRefs.find(F); if (BBFRI == BasicBlockFwdRefs.end()) { for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i) FunctionBBs[i] = BasicBlock::Create(Context, "", F); } else { auto &BBRefs = BBFRI->second; // Check for invalid basic block references. if (BBRefs.size() > FunctionBBs.size()) return error("Invalid ID"); IGC_ASSERT(!BBRefs.empty() && "Unexpected empty array"); IGC_ASSERT(!BBRefs.front() && "Invalid reference to entry block"); for (unsigned I = 0, E = FunctionBBs.size(), RE = BBRefs.size(); I != E; ++I) if (I < RE && BBRefs[I]) { BBRefs[I]->insertInto(F); FunctionBBs[I] = BBRefs[I]; } else { FunctionBBs[I] = BasicBlock::Create(Context, "", F); } // Erase from the table. BasicBlockFwdRefs.erase(BBFRI); } CurBB = FunctionBBs[0]; continue; } case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN // This record indicates that the last instruction is at the same // location as the previous instruction with a location. I = getLastInstruction(); if (!I) return error("Invalid record"); I->setDebugLoc(LastLoc); I = nullptr; continue; case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia] I = getLastInstruction(); if (!I || Record.size() < 4) return error("Invalid record"); unsigned Line = Record[0], Col = Record[1]; unsigned ScopeID = Record[2], IAID = Record[3]; bool isImplicitCode = Record.size() == 5 && Record[4]; MDNode *Scope = nullptr, *IA = nullptr; if (ScopeID) { Scope = dyn_cast_or_null( MDLoader->getMetadataFwdRefOrLoad(ScopeID - 1)); if (!Scope) return error("Invalid record"); } if (IAID) { IA = dyn_cast_or_null( MDLoader->getMetadataFwdRefOrLoad(IAID - 1)); if (!IA) return error("Invalid record"); } LastLoc = DebugLoc::get(Line, Col, Scope, IA, isImplicitCode); I->setDebugLoc(LastLoc); I = nullptr; continue; } case bitc::FUNC_CODE_INST_UNOP: { // UNOP: [opval, ty, opcode] unsigned OpNum = 0; Value *LHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || OpNum+1 > Record.size()) return error("Invalid record"); int Opc = getDecodedUnaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return error("Invalid record"); I = UnaryOperator::Create((Instruction::UnaryOps)Opc, LHS); InstructionList.push_back(I); if (OpNum < Record.size()) { if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } } break; } case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode] unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS) || OpNum+1 > Record.size()) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return error("Invalid record"); I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); InstructionList.push_back(I); if (OpNum < Record.size()) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) cast(I)->setHasNoSignedWrap(true); if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) cast(I)->setHasNoUnsignedWrap(true); } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } else if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } } break; } case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || OpNum+2 != Record.size()) return error("Invalid record"); Type *ResTy = getTypeByID(Record[OpNum]); int Opc = getDecodedCastOpcode(Record[OpNum + 1]); if (Opc == -1 || !ResTy) return error("Invalid record"); Instruction *Temp = nullptr; if ((I = UpgradeBitCastInst(Opc, Op, ResTy, Temp))) { if (Temp) { InstructionList.push_back(Temp); CurBB->getInstList().push_back(Temp); } } else { auto CastOp = (Instruction::CastOps)Opc; if (!CastInst::castIsValid(CastOp, Op, ResTy)) return error("Invalid cast"); I = CastInst::Create(CastOp, Op, ResTy); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD: case bitc::FUNC_CODE_INST_GEP_OLD: case bitc::FUNC_CODE_INST_GEP: { // GEP: type, [n x operands] unsigned OpNum = 0; Type *Ty; bool InBounds; if (BitCode == bitc::FUNC_CODE_INST_GEP) { InBounds = Record[OpNum++]; Ty = getTypeByID(Record[OpNum++]); } else { InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD; Ty = nullptr; } Value *BasePtr; if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr)) return error("Invalid record"); if (!Ty) Ty = cast(BasePtr->getType()->getScalarType()) ->getElementType(); else if (Ty != cast(BasePtr->getType()->getScalarType()) ->getElementType()) return error( "Explicit gep type does not match pointee type of pointer operand"); SmallVector GEPIdx; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); GEPIdx.push_back(Op); } I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx); InstructionList.push_back(I); if (InBounds) cast(I)->setIsInBounds(true); break; } case bitc::FUNC_CODE_INST_EXTRACTVAL: { // EXTRACTVAL: [opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("EXTRACTVAL: Invalid instruction with 0 indices"); SmallVector EXTRACTVALIdx; Type *CurTy = Agg->getType(); for (; OpNum != RecSize; ++OpNum) { bool IsArray = CurTy->isArrayTy(); bool IsStruct = CurTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("EXTRACTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= CurTy->getStructNumElements()) return error("EXTRACTVAL: Invalid struct index"); if (IsArray && Index >= CurTy->getArrayNumElements()) return error("EXTRACTVAL: Invalid array index"); EXTRACTVALIdx.push_back((unsigned)Index); if (IsStruct) CurTy = CurTy->getStructElementType(Index); else CurTy = CurTy->getArrayElementType(); } I = ExtractValueInst::Create(Agg, EXTRACTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTVAL: { // INSERTVAL: [opty, opval, opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) return error("Invalid record"); Value *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Val)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("INSERTVAL: Invalid instruction with 0 indices"); SmallVector INSERTVALIdx; Type *CurTy = Agg->getType(); for (; OpNum != RecSize; ++OpNum) { bool IsArray = CurTy->isArrayTy(); bool IsStruct = CurTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("INSERTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= CurTy->getStructNumElements()) return error("INSERTVAL: Invalid struct index"); if (IsArray && Index >= CurTy->getArrayNumElements()) return error("INSERTVAL: Invalid array index"); INSERTVALIdx.push_back((unsigned)Index); if (IsStruct) CurTy = CurTy->getStructElementType(Index); else CurTy = CurTy->getArrayElementType(); } if (CurTy != Val->getType()) return error("Inserted value type doesn't match aggregate type"); I = InsertValueInst::Create(Agg, Val, INSERTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval] // obsolete form of select // handles select i1 ... in old bitcode unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || popValue(Record, OpNum, NextValueNo, Type::getInt1Ty(Context), Cond)) return error("Invalid record"); I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred] // new form of select // handles select i1 or select [N x i1] unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || getValueTypePair(Record, OpNum, NextValueNo, Cond)) return error("Invalid record"); // select condition can be either i1 or [N x i1] if (VectorType* vector_type = dyn_cast(Cond->getType())) { // expect if (vector_type->getElementType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } else { // expect i1 if (Cond->getType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval] unsigned OpNum = 0; Value *Vec, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); I = ExtractElementInst::Create(Vec, Idx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval] unsigned OpNum = 0; Value *Vec, *Elt, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); if (popValue(Record, OpNum, NextValueNo, cast(Vec->getType())->getElementType(), Elt) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); I = InsertElementInst::Create(Vec, Elt, Idx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval] unsigned OpNum = 0; Value *Vec1, *Vec2, *Mask; if (getValueTypePair(Record, OpNum, NextValueNo, Vec1) || popValue(Record, OpNum, NextValueNo, Vec1->getType(), Vec2)) return error("Invalid record"); if (getValueTypePair(Record, OpNum, NextValueNo, Mask)) return error("Invalid record"); if (!Vec1->getType()->isVectorTy() || !Vec2->getType()->isVectorTy()) return error("Invalid type for value"); I = new ShuffleVectorInst(Vec1, Vec2, Mask); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred] // Old form of ICmp/FCmp returning bool // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were // both legal on vectors but had different behaviour. case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred] // FCmp/ICmp returning bool or vector of bool unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS)) return error("Invalid record"); unsigned PredVal = Record[OpNum]; bool IsFP = LHS->getType()->isFPOrFPVectorTy(); FastMathFlags FMF; if (IsFP && Record.size() > OpNum+1) FMF = getDecodedFastMathFlags(Record[++OpNum]); if (OpNum+1 != Record.size()) return error("Invalid record"); if (LHS->getType()->isFPOrFPVectorTy()) I = new FCmpInst((FCmpInst::Predicate)PredVal, LHS, RHS); else I = new ICmpInst((ICmpInst::Predicate)PredVal, LHS, RHS); if (FMF.any()) I->setFastMathFlags(FMF); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval] { unsigned Size = Record.size(); if (Size == 0) { I = ReturnInst::Create(Context); InstructionList.push_back(I); break; } unsigned OpNum = 0; Value *Op = nullptr; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); if (OpNum != Record.size()) return error("Invalid record"); I = ReturnInst::Create(Context, Op); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#] if (Record.size() != 1 && Record.size() != 3) return error("Invalid record"); BasicBlock *TrueDest = getBasicBlock(Record[0]); if (!TrueDest) return error("Invalid record"); if (Record.size() == 1) { I = BranchInst::Create(TrueDest); InstructionList.push_back(I); } else { BasicBlock *FalseDest = getBasicBlock(Record[1]); Value *Cond = getValue(Record, 2, NextValueNo, Type::getInt1Ty(Context)); if (!FalseDest || !Cond) return error("Invalid record"); I = BranchInst::Create(TrueDest, FalseDest, Cond); InstructionList.push_back(I); } break; } case bitc::FUNC_CODE_INST_CLEANUPRET: { // CLEANUPRET: [val] or [val,bb#] if (Record.size() != 1 && Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CleanupPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CleanupPad) return error("Invalid record"); BasicBlock *UnwindDest = nullptr; if (Record.size() == 2) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } I = CleanupReturnInst::Create(CleanupPad, UnwindDest); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHRET: { // CATCHRET: [val,bb#] if (Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CatchPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CatchPad) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); I = CatchReturnInst::Create(CatchPad, BB); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHSWITCH: { // CATCHSWITCH: [tok,num,(bb)*,bb?] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumHandlers = Record[Idx++]; SmallVector Handlers; for (unsigned Op = 0; Op != NumHandlers; ++Op) { BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); Handlers.push_back(BB); } BasicBlock *UnwindDest = nullptr; if (Idx + 1 == Record.size()) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } if (Record.size() != Idx) return error("Invalid record"); auto *CatchSwitch = CatchSwitchInst::Create(ParentPad, UnwindDest, NumHandlers); for (BasicBlock *Handler : Handlers) CatchSwitch->addHandler(Handler); I = CatchSwitch; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHPAD: case bitc::FUNC_CODE_INST_CLEANUPPAD: { // [tok,num,(ty,val)*] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumArgOperands = Record[Idx++]; SmallVector Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); Args.push_back(Val); } if (Record.size() != Idx) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_CLEANUPPAD) I = CleanupPadInst::Create(ParentPad, Args); else I = CatchPadInst::Create(ParentPad, Args); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...] // Check magic if ((Record[0] >> 16) == SWITCH_INST_MAGIC) { // "New" SwitchInst format with case ranges. The changes to write this // format were reverted but we still recognize bitcode that uses it. // Hopefully someday we will have support for case ranges and can use // this format again. Type *OpTy = getTypeByID(Record[1]); unsigned ValueBitWidth = cast(OpTy)->getBitWidth(); Value *Cond = getValue(Record, 2, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[3]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = Record[4]; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); unsigned CurIdx = 5; for (unsigned i = 0; i != NumCases; ++i) { SmallVector CaseVals; unsigned NumItems = Record[CurIdx++]; for (unsigned ci = 0; ci != NumItems; ++ci) { bool isSingleNumber = Record[CurIdx++]; APInt Low; unsigned ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; Low = readWideAPInt(makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; if (!isSingleNumber) { ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; APInt High = readWideAPInt( makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; // FIXME: It is not clear whether values in the range should be // compared as signed or unsigned values. The partially // implemented changes that used this format in the past used // unsigned comparisons. for ( ; Low.ule(High); ++Low) CaseVals.push_back(ConstantInt::get(Context, Low)); } else CaseVals.push_back(ConstantInt::get(Context, Low)); } BasicBlock *DestBB = getBasicBlock(Record[CurIdx++]); for (SmallVector::iterator cvi = CaseVals.begin(), cve = CaseVals.end(); cvi != cve; ++cvi) SI->addCase(*cvi, DestBB); } I = SI; break; } // Old SwitchInst format without case ranges. if (Record.size() < 3 || (Record.size() & 1) == 0) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Cond = getValue(Record, 1, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[2]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = (Record.size()-3)/2; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); for (unsigned i = 0, e = NumCases; i != e; ++i) { ConstantInt *CaseVal = dyn_cast_or_null(getFnValueByID(Record[3+i*2], OpTy)); BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]); if (!CaseVal || !DestBB) { delete SI; return error("Invalid record"); } SI->addCase(CaseVal, DestBB); } I = SI; break; } case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...] if (Record.size() < 2) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Address = getValue(Record, 1, NextValueNo, OpTy); if (!OpTy || !Address) return error("Invalid record"); unsigned NumDests = Record.size()-2; IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests); InstructionList.push_back(IBI); for (unsigned i = 0, e = NumDests; i != e; ++i) { if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) { IBI->addDestination(DestBB); } else { delete IBI; return error("Invalid record"); } } I = IBI; break; } case bitc::FUNC_CODE_INST_INVOKE: { // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...] if (Record.size() < 4) return error("Invalid record"); unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; BasicBlock *NormalBB = getBasicBlock(Record[OpNum++]); BasicBlock *UnwindBB = getBasicBlock(Record[OpNum++]); FunctionType *FTy = nullptr; if (CCInfo >> 13 & 1 && !(FTy = dyn_cast(getTypeByID(Record[OpNum++])))) return error("Explicit invoke type is not a function type"); Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) return error("Invalid record"); PointerType *CalleeTy = dyn_cast(Callee->getType()); if (!CalleeTy) return error("Callee is not a pointer"); if (!FTy) { FTy = dyn_cast(CalleeTy->getElementType()); if (!FTy) return error("Callee is not of pointer to function type"); } else if (CalleeTy->getElementType() != FTy) return error("Explicit invoke type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Ops; for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { Ops.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); if (!Ops.back()) return error("Invalid record"); } if (!FTy->isVarArg()) { if (Record.size() != OpNum) return error("Invalid record"); } else { // Read type/value pairs for varargs params. while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Ops.push_back(Op); } } I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops, OperandBundles); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast(CallingConv::MaxID & CCInfo)); cast(I)->setAttributes(PAL); break; } case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval] unsigned Idx = 0; Value *Val = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); I = ResumeInst::Create(Val); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE I = new UnreachableInst(Context); InstructionList.push_back(I); break; case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] if (Record.size() < 1 || ((Record.size()-1)&1)) return error("Invalid record"); Type *Ty = getTypeByID(Record[0]); if (!Ty) return error("Invalid record"); PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2); InstructionList.push_back(PN); for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) { Value *V; // With the new function encoding, it is possible that operands have // negative IDs (for forward references). Use a signed VBR // representation to keep the encoding small. if (UseRelativeIDs) V = getValueSigned(Record, 1+i, NextValueNo, Ty); else V = getValue(Record, 1+i, NextValueNo, Ty); BasicBlock *BB = getBasicBlock(Record[2+i]); if (!V || !BB) return error("Invalid record"); PN->addIncoming(V, BB); } I = PN; break; } case bitc::FUNC_CODE_INST_LANDINGPAD: case bitc::FUNC_CODE_INST_LANDINGPAD_OLD: { // LANDINGPAD: [ty, val, val, num, (id0,val0 ...)?] unsigned Idx = 0; if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD) { if (Record.size() < 3) return error("Invalid record"); } else { IGC_ASSERT(BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD); if (Record.size() < 4) return error("Invalid record"); } Type *Ty = getTypeByID(Record[Idx++]); if (!Ty) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD) { Value *PersFn = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, PersFn)) return error("Invalid record"); if (!F->hasPersonalityFn()) F->setPersonalityFn(cast(PersFn)); else if (F->getPersonalityFn() != cast(PersFn)) return error("Personality function mismatch"); } bool IsCleanup = !!Record[Idx++]; unsigned NumClauses = Record[Idx++]; LandingPadInst *LP = LandingPadInst::Create(Ty, NumClauses); LP->setCleanup(IsCleanup); for (unsigned J = 0; J != NumClauses; ++J) { LandingPadInst::ClauseType CT = LandingPadInst::ClauseType(Record[Idx++]); (void)CT; Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) { delete LP; return error("Invalid record"); } IGC_ASSERT((CT != LandingPadInst::Catch || !isa(Val->getType())) && "Catch clause has a invalid type!"); IGC_ASSERT((CT != LandingPadInst::Filter || isa(Val->getType())) && "Filter clause has invalid type!"); LP->addClause(cast(Val)); } I = LP; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align] if (Record.size() != 4) return error("Invalid record"); uint64_t AlignRecord = Record[3]; const uint64_t InAllocaMask = uint64_t(1) << 5; const uint64_t ExplicitTypeMask = uint64_t(1) << 6; const uint64_t SwiftErrorMask = uint64_t(1) << 7; const uint64_t FlagMask = InAllocaMask | ExplicitTypeMask | SwiftErrorMask; bool InAlloca = AlignRecord & InAllocaMask; bool SwiftError = AlignRecord & SwiftErrorMask; Type *Ty = getTypeByID(Record[0]); if ((AlignRecord & ExplicitTypeMask) == 0) { auto *PTy = dyn_cast_or_null(Ty); if (!PTy) return error("Old-style alloca with a non-pointer type"); Ty = PTy->getElementType(); } Type *OpTy = getTypeByID(Record[1]); Value *Size = getFnValueByID(Record[2], OpTy); unsigned Align; if (Error Err = parseAlignmentValue(AlignRecord & ~FlagMask, Align)) { return Err; } if (!Ty || !Size) return error("Invalid record"); // FIXME: Make this an optional field. const DataLayout &DL = TheModule->getDataLayout(); unsigned AS = DL.getAllocaAddrSpace(); AllocaInst *AI = new AllocaInst(Ty, AS, Size, Align); AI->setUsedWithInAlloca(InAlloca); AI->setSwiftError(SwiftError); I = AI; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || (OpNum + 2 != Record.size() && OpNum + 3 != Record.size())) return error("Invalid record"); Type *Ty = nullptr; if (OpNum + 3 == Record.size()) Ty = getTypeByID(Record[OpNum++]); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; if (!Ty) Ty = cast(Op->getType())->getElementType(); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Ty, Op, "", Record[OpNum + 1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOADATOMIC: { // LOADATOMIC: [opty, op, align, vol, ordering, ssid] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || (OpNum + 4 != Record.size() && OpNum + 5 != Record.size())) return error("Invalid record"); Type *Ty = nullptr; if (OpNum + 5 == Record.size()) Ty = getTypeByID(Record[OpNum++]); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; if (!Ty) Ty = cast(Op->getType())->getElementType(); AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Release || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Op, "", Record[OpNum+1], Align, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STORE: case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol] unsigned OpNum = 0; Value *Val, *Ptr; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || (BitCode == bitc::FUNC_CODE_INST_STORE ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val)) || OpNum + 2 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum+1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STOREATOMIC: case bitc::FUNC_CODE_INST_STOREATOMIC_OLD: { // STOREATOMIC: [ptrty, ptr, val, align, vol, ordering, ssid] unsigned OpNum = 0; Value *Val, *Ptr; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || !isa(Ptr->getType()) || (BitCode == bitc::FUNC_CODE_INST_STOREATOMIC ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val)) || OpNum + 4 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Acquire || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum+1], Align, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMPXCHG_OLD: case bitc::FUNC_CODE_INST_CMPXCHG: { // CMPXCHG:[ptrty, ptr, cmp, new, vol, successordering, ssid, // failureordering?, isweak?] unsigned OpNum = 0; Value *Ptr, *Cmp, *New; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || (BitCode == bitc::FUNC_CODE_INST_CMPXCHG ? getValueTypePair(Record, OpNum, NextValueNo, Cmp) : popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Cmp)) || popValue(Record, OpNum, NextValueNo, Cmp->getType(), New) || Record.size() < OpNum + 3 || Record.size() > OpNum + 5) return error("Invalid record"); AtomicOrdering SuccessOrdering = getDecodedOrdering(Record[OpNum + 1]); if (SuccessOrdering == AtomicOrdering::NotAtomic || SuccessOrdering == AtomicOrdering::Unordered) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 2]); if (Error Err = typeCheckLoadStoreInst(Cmp->getType(), Ptr->getType())) return Err; AtomicOrdering FailureOrdering; if (Record.size() < 7) FailureOrdering = AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrdering); else FailureOrdering = getDecodedOrdering(Record[OpNum + 3]); I = new AtomicCmpXchgInst(Ptr, Cmp, New, SuccessOrdering, FailureOrdering, SSID); cast(I)->setVolatile(Record[OpNum]); if (Record.size() < 8) { // Before weak cmpxchgs existed, the instruction simply returned the // value loaded from memory, so bitcode files from that era will be // expecting the first component of a modern cmpxchg. CurBB->getInstList().push_back(I); I = ExtractValueInst::Create(I, 0); } else { cast(I)->setWeak(Record[OpNum+4]); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ATOMICRMW: { // ATOMICRMW:[ptrty, ptr, val, op, vol, ordering, ssid] unsigned OpNum = 0; Value *Ptr, *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || !isa(Ptr->getType()) || popValue(Record, OpNum, NextValueNo, cast(Ptr->getType())->getElementType(), Val) || OpNum+4 != Record.size()) return error("Invalid record"); AtomicRMWInst::BinOp Operation = getDecodedRMWOperation(Record[OpNum]); if (Operation < AtomicRMWInst::FIRST_BINOP || Operation > AtomicRMWInst::LAST_BINOP) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); I = new AtomicRMWInst(Operation, Ptr, Val, Ordering, SSID); cast(I)->setVolatile(Record[OpNum+1]); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_FENCE: { // FENCE:[ordering, ssid] if (2 != Record.size()) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[0]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered || Ordering == AtomicOrdering::Monotonic) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[1]); I = new FenceInst(Context, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CALL: { // CALL: [paramattrs, cc, fmf, fnty, fnid, arg0, arg1...] if (Record.size() < 3) return error("Invalid record"); unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; FastMathFlags FMF; if ((CCInfo >> bitc::CALL_FMF) & 1) { FMF = getDecodedFastMathFlags(Record[OpNum++]); if (!FMF.any()) return error("Fast math flags indicator set for call with no FMF"); } FunctionType *FTy = nullptr; if (CCInfo >> bitc::CALL_EXPLICIT_TYPE & 1 && !(FTy = dyn_cast(getTypeByID(Record[OpNum++])))) return error("Explicit call type is not a function type"); Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) return error("Invalid record"); PointerType *OpTy = dyn_cast(Callee->getType()); if (!OpTy) return error("Callee is not a pointer type"); if (!FTy) { FTy = dyn_cast(OpTy->getElementType()); if (!FTy) return error("Callee is not of pointer to function type"); } else if (OpTy->getElementType() != FTy) return error("Explicit call type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Args; // Read the fixed params. for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { if (FTy->getParamType(i)->isLabelTy()) Args.push_back(getBasicBlock(Record[OpNum])); else Args.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); if (!Args.back()) return error("Invalid record"); } // Read type/value pairs for varargs params. if (!FTy->isVarArg()) { if (OpNum != Record.size()) return error("Invalid record"); } else { while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Args.push_back(Op); } } I = CallInst::Create(FTy, Callee, Args, OperandBundles); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast((0x7ff & CCInfo) >> bitc::CALL_CCONV)); CallInst::TailCallKind TCK = CallInst::TCK_None; if (CCInfo & 1 << bitc::CALL_TAIL) TCK = CallInst::TCK_Tail; if (CCInfo & (1 << bitc::CALL_MUSTTAIL)) TCK = CallInst::TCK_MustTail; if (CCInfo & (1 << bitc::CALL_NOTAIL)) TCK = CallInst::TCK_NoTail; cast(I)->setTailCallKind(TCK); cast(I)->setAttributes(PAL); if (FMF.any()) { if (!isa(I)) return error("Fast-math-flags specified for call without " "floating-point scalar or vector return type"); I->setFastMathFlags(FMF); } break; } case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty] if (Record.size() < 3) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Op = getValue(Record, 1, NextValueNo, OpTy); Type *ResTy = getTypeByID(Record[2]); if (!OpTy || !Op || !ResTy) return error("Invalid record"); I = new VAArgInst(Op, ResTy); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_OPERAND_BUNDLE: { // A call or an invoke can be optionally prefixed with some variable // number of operand bundle blocks. These blocks are read into // OperandBundles and consumed at the next call or invoke instruction. if (Record.size() < 1 || Record[0] >= BundleTags.size()) return error("Invalid record"); std::vector Inputs; unsigned OpNum = 1; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Inputs.push_back(Op); } OperandBundles.emplace_back(BundleTags[Record[0]], std::move(Inputs)); continue; } } // Add instruction to end of current BB. If there is no current BB, reject // this file. if (!CurBB) { I->deleteValue(); return error("Invalid instruction with no BB"); } if (!OperandBundles.empty()) { I->deleteValue(); return error("Operand bundles found with no consumer"); } CurBB->getInstList().push_back(I); // If this was a terminator instruction, move to the next block. if (I->isTerminator()) { ++CurBBNo; CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr; } // Non-void values get registered in the value table for future use. if (I && !I->getType()->isVoidTy()) ValueList.assignValue(I, NextValueNo++); } OutOfRecordLoop: if (!OperandBundles.empty()) return error("Operand bundles found with no consumer"); // Check the function list for unresolved values. if (Argument *A = dyn_cast(ValueList.back())) { if (!A->getParent()) { // We found at least one unresolved value. Nuke them all to avoid leaks. for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){ if ((A = dyn_cast_or_null(ValueList[i])) && !A->getParent()) { A->replaceAllUsesWith(UndefValue::get(A->getType())); delete A; } } return error("Never resolved value found in function"); } } // Unexpected unresolved metadata about to be dropped. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: outgoing forward refs"); // Trim the value list down to the size it was before we parsed this function. ValueList.shrinkTo(ModuleValueListSize); MDLoader->shrinkTo(ModuleMDLoaderSize); std::vector().swap(FunctionBBs); return Error::success(); } /// Find the function body in the bitcode stream Error BitcodeReader::findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator) { while (DeferredFunctionInfoIterator->second == 0) { // This is the fallback handling for the old format bitcode that // didn't contain the function index in the VST, or when we have // an anonymous function which would not have a VST entry. // Assert that we have one of those two cases. IGC_ASSERT(VSTOffset == 0 || !F->hasName()); // Parse the next body in the stream and set its position in the // DeferredFunctionInfo map. if (Error Err = rememberAndSkipFunctionBodies()) return Err; } return Error::success(); } SyncScope::ID BitcodeReader::getDecodedSyncScopeID(unsigned Val) { if (Val == SyncScope::SingleThread || Val == SyncScope::System) return SyncScope::ID(Val); if (Val >= SSIDs.size()) return SyncScope::System; // Map unknown synchronization scopes to system. return SSIDs[Val]; } //===----------------------------------------------------------------------===// // GVMaterializer implementation //===----------------------------------------------------------------------===// Error BitcodeReader::materialize(GlobalValue *GV) { Function *F = dyn_cast(GV); // If it's not a function or is already material, ignore the request. if (!F || !F->isMaterializable()) return Error::success(); DenseMap::iterator DFII = DeferredFunctionInfo.find(F); IGC_ASSERT(DFII != DeferredFunctionInfo.end() && "Deferred function not found!"); // If its position is recorded as 0, its body is somewhere in the stream // but we haven't seen it yet. if (DFII->second == 0) if (Error Err = findFunctionInStream(F, DFII)) return Err; // Materialize metadata before parsing any function bodies. if (Error Err = materializeMetadata()) return Err; // Move the bit stream to the saved position of the deferred function body. Stream.JumpToBit(DFII->second); if (Error Err = parseFunctionBody(F)) return Err; F->setIsMaterializable(false); if (StripDebugInfo) stripDebugInfo(*F); // Upgrade any old intrinsic calls in the function. for (auto &I : UpgradedIntrinsics) { for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) { User *U = *UI; ++UI; if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } } // Update calls to the remangled intrinsics for (auto &I : RemangledIntrinsics) for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) // Don't expect any other users than call sites CallSite(*UI++).setCalledFunction(I.second); // Finish fn->subprogram upgrade for materialized functions. if (DISubprogram *SP = MDLoader->lookupSubprogramForFunction(F)) F->setSubprogram(SP); // Check if the TBAA Metadata are valid, otherwise we will need to strip them. if (!MDLoader->isStrippingTBAA()) { for (auto &I : instructions(F)) { MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa); if (!TBAA || TBAAVerifyHelper.visitTBAAMetadata(I, TBAA)) continue; MDLoader->setStripTBAA(true); stripTBAA(F->getParent()); } } // Bring in any functions that this function forward-referenced via // blockaddresses. return materializeForwardReferencedFunctions(); } Error BitcodeReader::materializeModule() { if (Error Err = materializeMetadata()) return Err; // Promise to materialize all forward references. WillMaterializeAllForwardRefs = true; // Iterate over the module, deserializing any functions that are still on // disk. for (Function &F : *TheModule) { if (Error Err = materialize(&F)) return Err; } // At this point, if there are any function bodies, parse the rest of // the bits in the module past the last function block we have recorded // through either lazy scanning or the VST. if (LastFunctionBlockBit || NextUnreadBit) if (Error Err = parseModule(LastFunctionBlockBit > NextUnreadBit ? LastFunctionBlockBit : NextUnreadBit)) return Err; // Check that all block address forward references got resolved (as we // promised above). if (!BasicBlockFwdRefs.empty()) return error("Never resolved function from blockaddress"); // Upgrade any intrinsic calls that slipped through (should not happen!) and // delete the old functions to clean up. We can't do this unless the entire // module is materialized because there could always be another function body // with calls to the old function. for (auto &I : UpgradedIntrinsics) { for (auto *U : I.first->users()) { if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } if (!I.first->use_empty()) I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } UpgradedIntrinsics.clear(); // Do the same for remangled intrinsics for (auto &I : RemangledIntrinsics) { I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } RemangledIntrinsics.clear(); UpgradeDebugInfo(*TheModule); UpgradeModuleFlags(*TheModule); UpgradeRetainReleaseMarker(*TheModule); return Error::success(); } std::vector BitcodeReader::getIdentifiedStructTypes() const { return IdentifiedStructTypes; } ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader( BitstreamCursor Cursor, StringRef Strtab, ModuleSummaryIndex &TheIndex, StringRef ModulePath, unsigned ModuleId) : BitcodeReaderBase(std::move(Cursor), Strtab), TheIndex(TheIndex), ModulePath(ModulePath), ModuleId(ModuleId) {} void ModuleSummaryIndexBitcodeReader::addThisModule() { TheIndex.addModule(ModulePath, ModuleId); } ModuleSummaryIndex::ModuleInfo * ModuleSummaryIndexBitcodeReader::getThisModule() { return TheIndex.getModule(ModulePath); } std::pair ModuleSummaryIndexBitcodeReader::getValueInfoFromValueId(unsigned ValueId) { auto VGI = ValueIdToValueInfoMap[ValueId]; IGC_ASSERT(VGI.first); return VGI; } void ModuleSummaryIndexBitcodeReader::setValueGUID( uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage, StringRef SourceFileName) { std::string GlobalId = GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName); auto ValueGUID = GlobalValue::getGUID(GlobalId); auto OriginalNameID = ValueGUID; if (GlobalValue::isLocalLinkage(Linkage)) OriginalNameID = GlobalValue::getGUID(ValueName); // UseStrtab is false for legacy summary formats and value names are // created on stack. In that case we save the name in a string saver in // the index so that the value name can be recorded. ValueIdToValueInfoMap[ValueID] = std::make_pair( TheIndex.getOrInsertValueInfo( ValueGUID, UseStrtab ? ValueName : TheIndex.saveString(ValueName)), OriginalNameID); } // Specialized value symbol table parser used when reading module index // blocks where we don't actually create global values. The parsed information // is saved in the bitcode reader for use when later parsing summaries. Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap) { // With a strtab the VST is not required to parse the summary. if (UseStrtab) return Error::success(); IGC_ASSERT(Offset > 0 && "Expected non-zero VST offset"); uint64_t CurrentBit = jumpToValueSymbolTable(Offset, Stream); if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; // Read all the records for this value table. SmallString<128> ValueName; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // Done parsing VST, jump back to wherever we came from. Stream.JumpToBit(CurrentBit); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore (e.g. VST_CODE_BBENTRY records). break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] if (convertToString(Record, 1, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; setValueGUID(ValueID, ValueName, Linkage, SourceFileName); ValueName.clear(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] if (convertToString(Record, 2, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; setValueGUID(ValueID, ValueName, Linkage, SourceFileName); ValueName.clear(); break; } case bitc::VST_CODE_COMBINED_ENTRY: { // VST_CODE_COMBINED_ENTRY: [valueid, refguid] unsigned ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; // The "original name", which is the second value of the pair will be // overriden later by a FS_COMBINED_ORIGINAL_NAME in the combined index. ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(RefGUID), RefGUID); break; } } } } // Parse just the blocks needed for building the index out of the module. // At the end of this routine the module Index is populated with a map // from global value id to GlobalValueSummary objects. Error ModuleSummaryIndexBitcodeReader::parseModule() { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector Record; DenseMap ValueIdToLinkageMap; unsigned ValueId = 0; // Read the index for this module. while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::BLOCKINFO_BLOCK_ID: // Need to parse these to get abbrev ids (e.g. for VST) if (readBlockInfo()) return error("Malformed block"); break; case bitc::VALUE_SYMTAB_BLOCK_ID: // Should have been parsed earlier via VSTOffset, unless there // is no summary section. IGC_ASSERT(((SeenValueSymbolTable && VSTOffset > 0) || !SeenGlobalValSummary) && "Expected early VST parse via VSTOffset record"); if (Stream.SkipBlock()) return error("Invalid record"); break; case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID: // Add the module if it is a per-module index (has a source file name). if (!SourceFileName.empty()) addThisModule(); IGC_ASSERT(!SeenValueSymbolTable && "Already read VST when parsing summary block?"); // We might not have a VST if there were no values in the // summary. An empty summary block generated when we are // performing ThinLTO compiles so we don't later invoke // the regular LTO process on them. if (VSTOffset > 0) { if (Error Err = parseValueSymbolTable(VSTOffset, ValueIdToLinkageMap)) return Err; SeenValueSymbolTable = true; } SeenGlobalValSummary = true; if (Error Err = parseEntireSummary(Entry.ID)) return Err; break; case bitc::MODULE_STRTAB_BLOCK_ID: if (Error Err = parseModuleStringTable()) return Err; break; } continue; case BitstreamEntry::Record: { Record.clear(); auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { if (Error Err = parseVersionRecord(Record).takeError()) return Err; break; } /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: { SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); SourceFileName = ValueName.c_str(); break; } /// MODULE_CODE_HASH: [5*i32] case bitc::MODULE_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); auto &Hash = getThisModule()->second.second; int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); Hash[Pos++] = Val; } break; } /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one // word before the start of the identification or module block, which // was historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; // v1 GLOBALVAR: [pointer type, isconst, initid, linkage, ...] // v1 FUNCTION: [type, callingconv, isproto, linkage, ...] // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, ...] // v2: [strtab offset, strtab size, v1] case bitc::MODULE_CODE_GLOBALVAR: case bitc::MODULE_CODE_FUNCTION: case bitc::MODULE_CODE_ALIAS: { StringRef Name; ArrayRef GVRecord; std::tie(Name, GVRecord) = readNameFromStrtab(Record); if (GVRecord.size() <= 3) return error("Invalid record"); uint64_t RawLinkage = GVRecord[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); if (!UseStrtab) { ValueIdToLinkageMap[ValueId++] = Linkage; break; } setValueGUID(ValueId++, Name, Linkage, SourceFileName); break; } } } continue; } } } std::vector ModuleSummaryIndexBitcodeReader::makeRefList(ArrayRef Record) { std::vector Ret; Ret.reserve(Record.size()); for (uint64_t RefValueId : Record) Ret.push_back(getValueInfoFromValueId(RefValueId).first); return Ret; } std::vector ModuleSummaryIndexBitcodeReader::makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile, bool HasRelBF) { std::vector Ret; Ret.reserve(Record.size()); for (unsigned I = 0, E = Record.size(); I != E; ++I) { CalleeInfo::HotnessType Hotness = CalleeInfo::HotnessType::Unknown; uint64_t RelBF = 0; ValueInfo Callee = getValueInfoFromValueId(Record[I]).first; if (IsOldProfileFormat) { I += 1; // Skip old callsitecount field if (HasProfile) I += 1; // Skip old profilecount field } else if (HasProfile) Hotness = static_cast(Record[++I]); else if (HasRelBF) RelBF = Record[++I]; Ret.push_back(FunctionSummary::EdgeTy{Callee, CalleeInfo(Hotness, RelBF)}); } return Ret; } static void parseWholeProgramDevirtResolutionByArg(ArrayRef Record, size_t &Slot, WholeProgramDevirtResolution &Wpd) { uint64_t ArgNum = Record[Slot++]; WholeProgramDevirtResolution::ByArg &B = Wpd.ResByArg[{Record.begin() + Slot, Record.begin() + Slot + ArgNum}]; Slot += (size_t)ArgNum; B.TheKind = static_cast(Record[Slot++]); B.Info = Record[Slot++]; B.Byte = Record[Slot++]; B.Bit = Record[Slot++]; } static void parseWholeProgramDevirtResolution(ArrayRef Record, StringRef Strtab, size_t &Slot, TypeIdSummary &TypeId) { uint64_t Id = Record[Slot++]; WholeProgramDevirtResolution &Wpd = TypeId.WPDRes[Id]; Wpd.TheKind = static_cast(Record[Slot++]); Wpd.SingleImplName = {Strtab.data() + Record[Slot], static_cast(Record[Slot + 1])}; Slot += 2; uint64_t ResByArgNum = Record[Slot++]; for (uint64_t I = 0; I != ResByArgNum; ++I) parseWholeProgramDevirtResolutionByArg(Record, Slot, Wpd); } static void parseTypeIdSummaryRecord(ArrayRef Record, StringRef Strtab, ModuleSummaryIndex &TheIndex) { size_t Slot = 0; TypeIdSummary &TypeId = TheIndex.getOrInsertTypeIdSummary( {Strtab.data() + Record[Slot], static_cast(Record[Slot + 1])}); Slot += 2; TypeId.TTRes.TheKind = static_cast(Record[Slot++]); TypeId.TTRes.SizeM1BitWidth = Record[Slot++]; TypeId.TTRes.AlignLog2 = Record[Slot++]; TypeId.TTRes.SizeM1 = Record[Slot++]; TypeId.TTRes.BitMask = Record[Slot++]; TypeId.TTRes.InlineBits = Record[Slot++]; while (Slot < Record.size()) parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId); } static void setImmutableRefs(std::vector &Refs, unsigned Count) { // Read-only refs are in the end of the refs list. for (unsigned RefNo = Refs.size() - Count; RefNo < Refs.size(); ++RefNo) Refs[RefNo].setReadOnly(); } // Eagerly parse the entire summary block. This populates the GlobalValueSummary // objects in the index. Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { if (Stream.EnterSubBlock(ID)) return error("Invalid record"); SmallVector Record; // Parse version { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); if (Entry.Kind != BitstreamEntry::Record) return error("Invalid Summary Block: record for version expected"); if (Stream.readRecord(Entry.ID, Record) != bitc::FS_VERSION) return error("Invalid Summary Block: version expected"); } const uint64_t Version = Record[0]; const bool IsOldProfileFormat = Version == 1; if (Version < 1 || Version > 6) return error("Invalid summary version " + Twine(Version) + ". Version should be in the range [1-6]."); Record.clear(); // Keep around the last seen summary to be used when we see an optional // "OriginalName" attachement. GlobalValueSummary *LastSeenSummary = nullptr; GlobalValue::GUID LastSeenGUID = 0; // We can expect to see any number of type ID information records before // each function summary records; these variables store the information // collected so far so that it can be used to create the summary object. std::vector PendingTypeTests; std::vector PendingTypeTestAssumeVCalls, PendingTypeCheckedLoadVCalls; std::vector PendingTypeTestAssumeConstVCalls, PendingTypeCheckedLoadConstVCalls; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. The record format depends on whether this // is a per-module index or a combined index file. In the per-module // case the records contain the associated value's ID for correlation // with VST entries. In the combined index the correlation is done // via the bitcode offset of the summary records (which were saved // in the combined index VST entries). The records also contain // information used for ThinLTO renaming and importing. Record.clear(); auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: ignore. break; case bitc::FS_FLAGS: { // [flags] uint64_t Flags = Record[0]; // Scan flags. IGC_ASSERT(Flags <= 0x1f && "Unexpected bits in flag"); // 1 bit: WithGlobalValueDeadStripping flag. // Set on combined index only. if (Flags & 0x1) TheIndex.setWithGlobalValueDeadStripping(); // 1 bit: SkipModuleByDistributedBackend flag. // Set on combined index only. if (Flags & 0x2) TheIndex.setSkipModuleByDistributedBackend(); // 1 bit: HasSyntheticEntryCounts flag. // Set on combined index only. if (Flags & 0x4) TheIndex.setHasSyntheticEntryCounts(); // 1 bit: DisableSplitLTOUnit flag. // Set on per module indexes. It is up to the client to validate // the consistency of this flag across modules being linked. if (Flags & 0x8) TheIndex.setEnableSplitLTOUnit(); // 1 bit: PartiallySplitLTOUnits flag. // Set on combined index only. if (Flags & 0x10) TheIndex.setPartiallySplitLTOUnits(); break; } case bitc::FS_VALUE_GUID: { // [valueid, refguid] uint64_t ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(RefGUID), RefGUID); break; } // FS_PERMODULE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_PERMODULE_PROFILE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, // n x (valueid, hotness)] // FS_PERMODULE_RELBF: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, // n x (valueid, relblockfreq)] case bitc::FS_PERMODULE: case bitc::FS_PERMODULE_RELBF: case bitc::FS_PERMODULE_PROFILE: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned InstCount = Record[2]; uint64_t RawFunFlags = 0; unsigned NumRefs = Record[3]; unsigned NumImmutableRefs = 0; int RefListStartIndex = 4; if (Version >= 4) { RawFunFlags = Record[3]; NumRefs = Record[4]; RefListStartIndex = 5; if (Version >= 5) { NumImmutableRefs = Record[5]; RefListStartIndex = 6; } } auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_PERMODULE_PROFILE); bool HasRelBF = (BitCode == bitc::FS_PERMODULE_RELBF); std::vector Calls = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile, HasRelBF); setImmutableRefs(Refs, NumImmutableRefs); auto FS = llvm::make_unique( Flags, InstCount, getDecodedFFlags(RawFunFlags), /*EntryCount=*/0, std::move(Refs), std::move(Calls), std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeCheckedLoadConstVCalls)); PendingTypeTests.clear(); PendingTypeTestAssumeVCalls.clear(); PendingTypeCheckedLoadVCalls.clear(); PendingTypeTestAssumeConstVCalls.clear(); PendingTypeCheckedLoadConstVCalls.clear(); auto VIAndOriginalGUID = getValueInfoFromValueId(ValueID); FS->setModulePath(getThisModule()->first()); FS->setOriginalName(VIAndOriginalGUID.second); TheIndex.addGlobalValueSummary(VIAndOriginalGUID.first, std::move(FS)); break; } // FS_ALIAS: [valueid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_PERMODULE entries, as // they expect all aliasee summaries to be available. case bitc::FS_ALIAS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned AliaseeID = Record[2]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = llvm::make_unique(Flags); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. AS->setModulePath(getThisModule()->first()); GlobalValue::GUID AliaseeGUID = getValueInfoFromValueId(AliaseeID).first.getGUID(); auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeGUID, ModulePath); if (!AliaseeInModule) return error("Alias expects aliasee summary to be parsed"); AS->setAliasee(AliaseeInModule); AS->setAliaseeGUID(AliaseeGUID); auto GUID = getValueInfoFromValueId(ValueID); AS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(AS)); break; } // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags, n x valueid] case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned RefArrayStart = 2; GlobalVarSummary::GVarFlags GVF; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[2]); RefArrayStart = 3; } std::vector Refs = makeRefList(ArrayRef(Record).slice(RefArrayStart)); auto FS = llvm::make_unique(Flags, GVF, std::move(Refs)); FS->setModulePath(getThisModule()->first()); auto GUID = getValueInfoFromValueId(ValueID); FS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(FS)); break; } // FS_COMBINED: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid, hotness)] case bitc::FS_COMBINED: case bitc::FS_COMBINED_PROFILE: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned InstCount = Record[3]; uint64_t RawFunFlags = 0; uint64_t EntryCount = 0; unsigned NumRefs = Record[4]; unsigned NumImmutableRefs = 0; int RefListStartIndex = 5; if (Version >= 4) { RawFunFlags = Record[4]; RefListStartIndex = 6; size_t NumRefsIndex = 5; if (Version >= 5) { RefListStartIndex = 7; if (Version >= 6) { NumRefsIndex = 6; EntryCount = Record[5]; RefListStartIndex = 8; } NumImmutableRefs = Record[RefListStartIndex - 1]; } NumRefs = Record[NumRefsIndex]; } auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_COMBINED_PROFILE); std::vector Edges = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile, false); ValueInfo VI = getValueInfoFromValueId(ValueID).first; setImmutableRefs(Refs, NumImmutableRefs); auto FS = llvm::make_unique( Flags, InstCount, getDecodedFFlags(RawFunFlags), EntryCount, std::move(Refs), std::move(Edges), std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeCheckedLoadConstVCalls)); PendingTypeTests.clear(); PendingTypeTestAssumeVCalls.clear(); PendingTypeCheckedLoadVCalls.clear(); PendingTypeTestAssumeConstVCalls.clear(); PendingTypeCheckedLoadConstVCalls.clear(); LastSeenSummary = FS.get(); LastSeenGUID = VI.getGUID(); FS->setModulePath(ModuleIdMap[ModuleId]); TheIndex.addGlobalValueSummary(VI, std::move(FS)); break; } // FS_COMBINED_ALIAS: [valueid, modid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_COMBINED entries, as // they expect all aliasee summaries to be available. case bitc::FS_COMBINED_ALIAS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned AliaseeValueId = Record[3]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = llvm::make_unique(Flags); LastSeenSummary = AS.get(); AS->setModulePath(ModuleIdMap[ModuleId]); auto AliaseeGUID = getValueInfoFromValueId(AliaseeValueId).first.getGUID(); auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeGUID, AS->modulePath()); AS->setAliasee(AliaseeInModule); AS->setAliaseeGUID(AliaseeGUID); ValueInfo VI = getValueInfoFromValueId(ValueID).first; LastSeenGUID = VI.getGUID(); TheIndex.addGlobalValueSummary(VI, std::move(AS)); break; } // FS_COMBINED_GLOBALVAR_INIT_REFS: [valueid, modid, flags, n x valueid] case bitc::FS_COMBINED_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned RefArrayStart = 3; GlobalVarSummary::GVarFlags GVF; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[3]); RefArrayStart = 4; } std::vector Refs = makeRefList(ArrayRef(Record).slice(RefArrayStart)); auto FS = llvm::make_unique(Flags, GVF, std::move(Refs)); LastSeenSummary = FS.get(); FS->setModulePath(ModuleIdMap[ModuleId]); ValueInfo VI = getValueInfoFromValueId(ValueID).first; LastSeenGUID = VI.getGUID(); TheIndex.addGlobalValueSummary(VI, std::move(FS)); break; } // FS_COMBINED_ORIGINAL_NAME: [original_name] case bitc::FS_COMBINED_ORIGINAL_NAME: { uint64_t OriginalName = Record[0]; if (!LastSeenSummary) return error("Name attachment that does not follow a combined record"); LastSeenSummary->setOriginalName(OriginalName); TheIndex.addOriginalName(LastSeenGUID, OriginalName); // Reset the LastSeenSummary LastSeenSummary = nullptr; LastSeenGUID = 0; break; } case bitc::FS_TYPE_TESTS: IGC_ASSERT(PendingTypeTests.empty()); PendingTypeTests.insert(PendingTypeTests.end(), Record.begin(), Record.end()); break; case bitc::FS_TYPE_TEST_ASSUME_VCALLS: IGC_ASSERT(PendingTypeTestAssumeVCalls.empty()); for (unsigned I = 0; I != Record.size(); I += 2) PendingTypeTestAssumeVCalls.push_back({Record[I], Record[I+1]}); break; case bitc::FS_TYPE_CHECKED_LOAD_VCALLS: IGC_ASSERT(PendingTypeCheckedLoadVCalls.empty()); for (unsigned I = 0; I != Record.size(); I += 2) PendingTypeCheckedLoadVCalls.push_back({Record[I], Record[I+1]}); break; case bitc::FS_TYPE_TEST_ASSUME_CONST_VCALL: PendingTypeTestAssumeConstVCalls.push_back( {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; case bitc::FS_TYPE_CHECKED_LOAD_CONST_VCALL: PendingTypeCheckedLoadConstVCalls.push_back( {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; case bitc::FS_CFI_FUNCTION_DEFS: { std::set &CfiFunctionDefs = TheIndex.cfiFunctionDefs(); for (unsigned I = 0; I != Record.size(); I += 2) CfiFunctionDefs.insert( {Strtab.data() + Record[I], static_cast(Record[I + 1])}); break; } case bitc::FS_CFI_FUNCTION_DECLS: { std::set &CfiFunctionDecls = TheIndex.cfiFunctionDecls(); for (unsigned I = 0; I != Record.size(); I += 2) CfiFunctionDecls.insert( {Strtab.data() + Record[I], static_cast(Record[I + 1])}); break; } case bitc::FS_TYPE_ID: parseTypeIdSummaryRecord(Record, Strtab, TheIndex); break; } } llvm_unreachable("Exit infinite loop"); } // Parse the module string table block into the Index. // This populates the ModulePathStringTable map in the index. Error ModuleSummaryIndexBitcodeReader::parseModuleStringTable() { if (Stream.EnterSubBlock(bitc::MODULE_STRTAB_BLOCK_ID)) return error("Invalid record"); SmallVector Record; SmallString<128> ModulePath; ModuleSummaryIndex::ModuleInfo *LastSeenModule = nullptr; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } Record.clear(); switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore. break; case bitc::MST_CODE_ENTRY: { // MST_ENTRY: [modid, namechar x N] uint64_t ModuleId = Record[0]; if (convertToString(Record, 1, ModulePath)) return error("Invalid record"); LastSeenModule = TheIndex.addModule(ModulePath, ModuleId); ModuleIdMap[ModuleId] = LastSeenModule->first(); ModulePath.clear(); break; } /// MST_CODE_HASH: [5*i32] case bitc::MST_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); if (!LastSeenModule) return error("Invalid hash that does not follow a module path"); int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); LastSeenModule->second.second[Pos++] = Val; } // Reset LastSeenModule to avoid overriding the hash unexpectedly. LastSeenModule = nullptr; break; } } } llvm_unreachable("Exit infinite loop"); } namespace upgrader { // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. class BitcodeErrorCategoryType : public std::error_category { const char *name() const noexcept override { return "llvm.bitcode"; } std::string message(int IE) const override { BitcodeError E = static_cast(IE); switch (E) { case BitcodeError::CorruptedBitcode: return "Corrupted bitcode"; } llvm_unreachable("Unknown error type!"); } }; static ManagedStatic ErrorCategory; const std::error_category &BitcodeErrorCategory() { return *ErrorCategory; } static Expected readBlobInRecord(BitstreamCursor &Stream, unsigned Block, unsigned RecordID) { if (Stream.EnterSubBlock(Block)) return error("Invalid record"); StringRef Strtab; while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: return Strtab; case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Stream.SkipBlock()) return error("Malformed block"); break; case BitstreamEntry::Record: StringRef Blob; SmallVector Record; if (Stream.readRecord(Entry.ID, Record, &Blob) == RecordID) Strtab = Blob; break; } } } //===----------------------------------------------------------------------===// // External interface //===----------------------------------------------------------------------===// Expected> getBitcodeModuleList(MemoryBufferRef Buffer) { auto FOrErr = upgrader::getBitcodeFileContents(Buffer); if (!FOrErr) return FOrErr.takeError(); return std::move(FOrErr->Mods); } Expected getBitcodeFileContents(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); BitstreamCursor &Stream = *StreamOrErr; BitcodeFileContents F; while (true) { uint64_t BCBegin = Stream.getCurrentByteNo(); // We may be consuming bitcode from a client that leaves garbage at the end // of the bitcode stream. If we are close enough to // the end that there cannot possibly be another module, stop looking. if (BCBegin + 8 >= Stream.getBitcodeBytes().size()) return F; BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: { uint64_t IdentificationBit = -1ull; if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) { IdentificationBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Stream.SkipBlock()) return error("Malformed block"); Entry = Stream.advance(); if (Entry.Kind != BitstreamEntry::SubBlock || Entry.ID != bitc::MODULE_BLOCK_ID) return error("Malformed block"); } if (Entry.ID == bitc::MODULE_BLOCK_ID) { uint64_t ModuleBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Stream.SkipBlock()) return error("Malformed block"); F.Mods.push_back({ Stream.getBitcodeBytes().slice( BCBegin, Stream.getCurrentByteNo() - BCBegin), Buffer.getBufferIdentifier(), IdentificationBit, ModuleBit }); continue; } if (Entry.ID == bitc::STRTAB_BLOCK_ID) { Expected Strtab = readBlobInRecord(Stream, bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB); if (!Strtab) return Strtab.takeError(); // This string table is used by every preceding bitcode module that does // not have its own string table. A bitcode file may have multiple // string tables if it was created by binary concatenation, for example // with "llvm-cat -b". for (auto I = F.Mods.rbegin(), E = F.Mods.rend(); I != E; ++I) { if (!I->Strtab.empty()) break; I->Strtab = *Strtab; } // Similarly, the string table is used by every preceding symbol table; // normally there will be just one unless the bitcode file was created // by binary concatenation. if (!F.Symtab.empty() && F.StrtabForSymtab.empty()) F.StrtabForSymtab = *Strtab; continue; } if (Entry.ID == bitc::SYMTAB_BLOCK_ID) { Expected SymtabOrErr = readBlobInRecord(Stream, bitc::SYMTAB_BLOCK_ID, bitc::SYMTAB_BLOB); if (!SymtabOrErr) return SymtabOrErr.takeError(); // We can expect the bitcode file to have multiple symbol tables if it // was created by binary concatenation. In that case we silently // ignore any subsequent symbol tables, which is fine because this is a // low level function. The client is expected to notice that the number // of modules in the symbol table does not match the number of modules // in the input file and regenerate the symbol table. if (F.Symtab.empty()) F.Symtab = *SymtabOrErr; continue; } if (Stream.SkipBlock()) return error("Malformed block"); continue; } case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } /// Get a lazy one-at-time loading module from bitcode. /// /// This isn't always used in a lazy context. In particular, it's also used by /// \a parseModule(). If this is truly lazy, then we need to eagerly pull /// in forward-referenced functions from block address references. /// /// \param[in] MaterializeAll Set to \c true if we should materialize /// everything. Expected> BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting) { BitstreamCursor Stream(Buffer); std::string ProducerIdentification; if (IdentificationBit != -1ull) { Stream.JumpToBit(IdentificationBit); Expected ProducerIdentificationOrErr = readIdentificationBlock(Stream); if (!ProducerIdentificationOrErr) return ProducerIdentificationOrErr.takeError(); ProducerIdentification = *ProducerIdentificationOrErr; } Stream.JumpToBit(ModuleBit); auto *R = new BitcodeReader(std::move(Stream), Strtab, ProducerIdentification, Context); std::unique_ptr M = llvm::make_unique(ModuleIdentifier, Context); M->setMaterializer(R); // Delay parsing Metadata if ShouldLazyLoadMetadata is true. if (Error Err = R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata, IsImporting)) return std::move(Err); if (MaterializeAll) { // Read in the entire module, and destroy the BitcodeReader. if (Error Err = M->materializeAll()) return std::move(Err); } else { // Resolve forward references from blockaddresses. if (Error Err = R->materializeForwardReferencedFunctions()) return std::move(Err); } return std::move(M); } Expected> BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { return getModuleImpl(Context, false, ShouldLazyLoadMetadata, IsImporting); } // Parse the specified bitcode buffer and merge the index into CombinedIndex. // We don't use ModuleIdentifier here because the client may need to control the // module path used in the combined summary (e.g. when reading summaries for // regular LTO modules). Error BitcodeModule::readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, uint64_t ModuleId) { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, CombinedIndex, ModulePath, ModuleId); return R.parseModule(); } // Parse the specified bitcode buffer, returning the function info index. Expected> BitcodeModule::getSummary() { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); auto Index = llvm::make_unique(/*HaveGVs=*/false); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, *Index, ModuleIdentifier, 0); if (Error Err = R.parseModule()) return std::move(Err); return std::move(Index); } static Expected getEnableSplitLTOUnitFlag(BitstreamCursor &Stream, unsigned ID) { if (Stream.EnterSubBlock(ID)) return error("Invalid record"); SmallVector Record; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // If no flags record found, conservatively return true to mimic // behavior before this flag was added. return true; case BitstreamEntry::Record: // The interesting case. break; } // Look for the FS_FLAGS record. Record.clear(); auto BitCode = Stream.readRecord(Entry.ID, Record); switch (BitCode) { default: // Default behavior: ignore. break; case bitc::FS_FLAGS: { // [flags] uint64_t Flags = Record[0]; // Scan flags. IGC_ASSERT(Flags <= 0x1f && "Unexpected bits in flag"); return Flags & 0x8; } } } llvm_unreachable("Exit infinite loop"); } // Check if the given bitcode buffer contains a global value summary block. Expected BitcodeModule::getLTOInfo() { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); while (true) { BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false, /*EnableSplitLTOUnit=*/false }; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) { Expected EnableSplitLTOUnit = getEnableSplitLTOUnitFlag(Stream, Entry.ID); if (!EnableSplitLTOUnit) return EnableSplitLTOUnit.takeError(); return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true, *EnableSplitLTOUnit }; } if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) { Expected EnableSplitLTOUnit = getEnableSplitLTOUnitFlag(Stream, Entry.ID); if (!EnableSplitLTOUnit) return EnableSplitLTOUnit.takeError(); return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true, *EnableSplitLTOUnit }; } // Ignore other sub-blocks. if (Stream.SkipBlock()) return error("Malformed block"); continue; case BitstreamEntry::Record: Stream.skipRecord(Entry.ID); continue; } } } static Expected getSingleModule(MemoryBufferRef Buffer) { Expected> MsOrErr = upgrader::getBitcodeModuleList(Buffer); if (!MsOrErr) return MsOrErr.takeError(); if (MsOrErr->size() != 1) return error("Expected a single module"); return (*MsOrErr)[0]; } Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLazyModule(Context, ShouldLazyLoadMetadata, IsImporting); } Expected> getOwningLazyBitcodeModule( std::unique_ptr &&Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { auto MOrErr = upgrader::getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata, IsImporting); if (MOrErr) (*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer)); return MOrErr; } Expected> BitcodeModule::parseModule(LLVMContext &Context) { return getModuleImpl(Context, true, false, false); // TODO: Restore the use-lists to the in-memory state when the bitcode was // written. We must defer until the Module has been fully materialized. } Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->parseModule(Context); } Expected getBitcodeTargetTriple(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readTriple(*StreamOrErr); } Expected isBitcodeContainingObjCCategory(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return hasObjCCategory(*StreamOrErr); } Expected getBitcodeProducerString(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readIdentificationCode(*StreamOrErr); } Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, uint64_t ModuleId) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->readSummary(CombinedIndex, BM->getModuleIdentifier(), ModuleId); } Expected> getModuleSummaryIndex(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getSummary(); } Expected getBitcodeLTOInfo(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLTOInfo(); } Expected> getModuleSummaryIndexForFile(StringRef Path, bool IgnoreEmptyThinLTOIndexFile) { ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path); if (!FileOrErr) return errorCodeToError(FileOrErr.getError()); if (IgnoreEmptyThinLTOIndexFile && !(*FileOrErr)->getBufferSize()) return nullptr; return upgrader::getModuleSummaryIndex(**FileOrErr); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm8/BitcodeReader.h000066400000000000000000000171301363533017100272510ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- llvm/Bitcode/BitcodeReader.h - Bitcode reader ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This header defines interfaces to read LLVM bitcode files/streams. // //===----------------------------------------------------------------------===// #ifndef __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #define __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #include "common/LLVMWarningsPush.hpp" #include #include #include #include "llvm/Bitcode/BitcodeReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common/LLVMWarningsPop.hpp" namespace upgrader { using namespace llvm; struct BitcodeFileContents; /// Basic information extracted from a bitcode module to be used for LTO. struct BitcodeLTOInfo { bool IsThinLTO; bool HasSummary; bool EnableSplitLTOUnit; }; /// Represents a module in a bitcode file. class BitcodeModule { // This covers the identification (if present) and module blocks. ArrayRef Buffer; StringRef ModuleIdentifier; // The string table used to interpret this module. StringRef Strtab; // The bitstream location of the IDENTIFICATION_BLOCK. uint64_t IdentificationBit; // The bitstream location of this module's MODULE_BLOCK. uint64_t ModuleBit; BitcodeModule(ArrayRef Buffer, StringRef ModuleIdentifier, uint64_t IdentificationBit, uint64_t ModuleBit) : Buffer(Buffer), ModuleIdentifier(ModuleIdentifier), IdentificationBit(IdentificationBit), ModuleBit(ModuleBit) {} // Calls the ctor. friend Expected getBitcodeFileContents(MemoryBufferRef Buffer); Expected> getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting); public: StringRef getBuffer() const { return StringRef((const char *)Buffer.begin(), Buffer.size()); } StringRef getStrtab() const { return Strtab; } StringRef getModuleIdentifier() const { return ModuleIdentifier; } /// Read the bitcode module and prepare for lazy deserialization of function /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well. /// If IsImporting is true, this module is being parsed for ThinLTO /// importing into another module. Expected> getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting); /// Read the entire bitcode module and return it. Expected> parseModule(LLVMContext &Context); /// Returns information about the module to be used for LTO: whether to /// compile with ThinLTO, and whether it has a summary. Expected getLTOInfo(); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getSummary(); /// Parse the specified bitcode buffer and merge its module summary index /// into CombinedIndex. Error readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, uint64_t ModuleId); }; struct BitcodeFileContents { std::vector Mods; StringRef Symtab, StrtabForSymtab; }; /// Returns the contents of a bitcode file. This includes the raw contents of /// the symbol table embedded in the bitcode file. Clients which require a /// symbol table should prefer to use irsymtab::read instead of this function /// because it creates a reader for the irsymtab and handles upgrading bitcode /// files without a symbol table or with an old symbol table. Expected getBitcodeFileContents(MemoryBufferRef Buffer); /// Returns a list of modules in the specified bitcode buffer. Expected> getBitcodeModuleList(MemoryBufferRef Buffer); /// Read the header of the specified bitcode buffer and prepare for lazy /// deserialization of function bodies. If ShouldLazyLoadMetadata is true, /// lazily load metadata as well. If IsImporting is true, this module is /// being parsed for ThinLTO importing into another module. Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); /// Read the specified bitcode file, returning the module. Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); /// Returns LTO information for the specified bitcode file. Expected getBitcodeLTOInfo(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getModuleSummaryIndex(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer and merge the index into CombinedIndex. Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, uint64_t ModuleId); /// Parse the module summary index out of an IR file and return the module /// summary index object if found, or an empty summary if not. If Path refers /// to an empty file and IgnoreEmptyThinLTOIndexFile is true, then /// this function will return nullptr. Expected> getModuleSummaryIndexForFile(StringRef Path, bool IgnoreEmptyThinLTOIndexFile = false); } // end namespace llvm #endif intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm8/MetadataLoader.h000066400000000000000000000074161363533017100274320ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===-- Bitcode/Reader/MetadataLoader.h - Load Metadatas -------*- C++ -*-====// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class handles loading Metadatas. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_METADATALOADER_H #define LLVM_LIB_BITCODE_READER_METADATALOADER_H #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Error.h" #include #include namespace llvm { class BitcodeReaderValueList; class BitstreamCursor; class DISubprogram; class Error; class Function; class Instruction; class Metadata; class MDNode; class Module; class Type; /// Helper class that handles loading Metadatas and keeping them available. class MetadataLoader { class MetadataLoaderImpl; std::unique_ptr Pimpl; Error parseMetadata(bool ModuleLevel); public: ~MetadataLoader(); MetadataLoader(BitstreamCursor &Stream, Module &TheModule, BitcodeReaderValueList &ValueList, bool IsImporting, std::function getTypeByID); MetadataLoader &operator=(MetadataLoader &&); MetadataLoader(MetadataLoader &&); // Parse a module metadata block Error parseModuleMetadata() { return parseMetadata(true); } // Parse a function metadata block Error parseFunctionMetadata() { return parseMetadata(false); } /// Set the mode to strip TBAA metadata on load. void setStripTBAA(bool StripTBAA = true); /// Return true if the Loader is stripping TBAA metadata. bool isStrippingTBAA(); // Return true there are remaining unresolved forward references. bool hasFwdRefs() const; /// Return the given metadata, creating a replaceable forward reference if /// necessary. Metadata *getMetadataFwdRefOrLoad(unsigned Idx); /// Return the DISubprogram metadata for a Function if any, null otherwise. DISubprogram *lookupSubprogramForFunction(Function *F); /// Parse a `METADATA_ATTACHMENT` block for a function. Error parseMetadataAttachment( Function &F, const SmallVectorImpl &InstructionList); /// Parse a `METADATA_KIND` block for the current module. Error parseMetadataKinds(); unsigned size() const; void shrinkTo(unsigned N); /// Perform bitcode upgrades on llvm.dbg.* calls. void upgradeDebugIntrinsics(Function &F); }; } #endif // LLVM_LIB_BITCODE_READER_METADATALOADER_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm8/Upgrader.cpp000066400000000000000000000043221363533017100266600ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "Upgrader.h" #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include #include #include "common/LLVMWarningsPop.hpp" using namespace llvm; std::unique_ptr upgrader::upgradeBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { auto ErrM = upgrader::parseBitcodeFile(Buffer, Context); Module *M = ErrM.get().get(); if (!M) return nullptr; SmallVector Buf; Buf.reserve(1024*1024); raw_svector_ostream OS(Buf); WriteBitcodeToFile(*M, OS); return MemoryBuffer::getMemBufferCopy(OS.str()); } Expected> upgrader::upgradeAndParseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { return upgrader::parseBitcodeFile(Buffer, Context); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm8/Upgrader.h000066400000000000000000000036741363533017100263360ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #ifndef __DRIVERINTERFACE_UPGRADER_H__ #define __DRIVERINTERFACE_UPGRADER_H__ #include "common/LLVMWarningsPush.hpp" #include #include #include #include #include "common/LLVMWarningsPop.hpp" namespace upgrader { llvm::Expected> parseBitcodeFile(llvm::MemoryBufferRef Buffer, llvm::LLVMContext &Context); std::unique_ptr upgradeBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); llvm::Expected> upgradeAndParseBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); } // End upgrader namespace #endif // __DRIVERINTERFACE_UPGRADER_H__ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm8/ValueList.h000066400000000000000000000073301363533017100264660ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===-- Bitcode/Reader/ValueList.h - Number values --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class gives values and types Unique ID's. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_VALUELIST_H #define LLVM_LIB_BITCODE_READER_VALUELIST_H #include "llvm/IR/ValueHandle.h" #include #include #include "Probe.h" namespace llvm { class Constant; class LLVMContext; class Type; class Value; class BitcodeReaderValueList { std::vector ValuePtrs; /// As we resolve forward-referenced constants, we add information about them /// to this vector. This allows us to resolve them in bulk instead of /// resolving each reference at a time. See the code in /// ResolveConstantForwardRefs for more information about this. /// /// The key of this vector is the placeholder constant, the value is the slot /// number that holds the resolved value. using ResolveConstantsTy = std::vector>; ResolveConstantsTy ResolveConstants; LLVMContext &Context; public: BitcodeReaderValueList(LLVMContext &C) : Context(C) {} ~BitcodeReaderValueList() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); } // vector compatibility methods unsigned size() const { return ValuePtrs.size(); } void resize(unsigned N) { ValuePtrs.resize(N); } void push_back(Value *V) { ValuePtrs.emplace_back(V); } void clear() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); ValuePtrs.clear(); } Value *operator[](unsigned i) const { IGC_ASSERT(i < ValuePtrs.size()); return ValuePtrs[i]; } Value *back() const { return ValuePtrs.back(); } void pop_back() { ValuePtrs.pop_back(); } bool empty() const { return ValuePtrs.empty(); } void shrinkTo(unsigned N) { IGC_ASSERT(N <= size() && "Invalid shrinkTo request!"); ValuePtrs.resize(N); } Constant *getConstantFwdRef(unsigned Idx, Type *Ty); Value *getValueFwdRef(unsigned Idx, Type *Ty); void assignValue(Value *V, unsigned Idx); /// Once all constants are read, this method bulk resolves any forward /// references. void resolveConstantForwardRefs(); }; } // end namespace llvm #endif // LLVM_LIB_BITCODE_READER_VALUELIST_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm9/000077500000000000000000000000001363533017100244035ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm9/BitcodeReader.cpp000066400000000000000000007444501363533017100276210ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ //===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "MetadataLoader.h" #include "ValueList.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalIndirectSymbol.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "common/LLVMWarningsPop.hpp" #include "BitcodeReader.h" #include "Probe.h" using namespace llvm; //===----------------------------------------------------------------------===// // upgrade bitcast to addrspacecast when necessary //===----------------------------------------------------------------------===// Instruction *upgradeBitCastInst(unsigned Opc, Value *V, Type *DestTy, Instruction *&Temp) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = V->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return CastInst::Create(Instruction::AddrSpaceCast, V, DestTy); } return nullptr; } Value *upgradeBitCastExpr(unsigned Opc, Constant *C, Type *DestTy) { if (Opc != Instruction::BitCast) return nullptr; Type *SrcTy = C->getType(); if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { // Convert it to 'addrspacecast' instead. return ConstantExpr::getAddrSpaceCast(C, DestTy); } return nullptr; } namespace { enum { SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; } // end anonymous namespace static Error error(const Twine &Message) { return make_error( Message, make_error_code(BitcodeError::CorruptedBitcode)); } static Error hasInvalidBitcodeHeader(BitstreamCursor &Stream) { if (!Stream.canSkipToPos(4)) return createStringError(std::errc::illegal_byte_sequence, "file too small to contain bitcode header"); for (unsigned C : {'B', 'C'}) if (Expected Res = Stream.Read(8)) { if (Res.get() != C) return createStringError(std::errc::illegal_byte_sequence, "file doesn't start with bitcode header"); } else return Res.takeError(); for (unsigned C : {0x0, 0xC, 0xE, 0xD}) if (Expected Res = Stream.Read(4)) { if (Res.get() != C) return createStringError(std::errc::illegal_byte_sequence, "file doesn't start with bitcode header"); } else return Res.takeError(); return Error::success(); } static Expected initStream(MemoryBufferRef Buffer) { const unsigned char *BufPtr = (const unsigned char *)Buffer.getBufferStart(); const unsigned char *BufEnd = BufPtr + Buffer.getBufferSize(); if (Buffer.getBufferSize() & 3) return error("Invalid bitcode signature"); // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. if (isBitcodeWrapper(BufPtr, BufEnd)) if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) return error("Invalid bitcode wrapper header"); BitstreamCursor Stream(ArrayRef(BufPtr, BufEnd)); if (Error Err = hasInvalidBitcodeHeader(Stream)) return std::move(Err); return std::move(Stream); } /// Convert a string from a record into an std::string, return true on failure. template static bool convertToString(ArrayRef Record, unsigned Idx, StrTy &Result) { if (Idx > Record.size()) return true; for (unsigned i = Idx, e = Record.size(); i != e; ++i) Result += (char)Record[i]; return false; } // Strip all the TBAA attachment for the module. static void stripTBAA(Module *M) { for (auto &F : *M) { if (F.isMaterializable()) continue; for (auto &I : instructions(F)) I.setMetadata(LLVMContext::MD_tbaa, nullptr); } } /// Read the "IDENTIFICATION_BLOCK_ID" block, do some basic enforcement on the /// "epoch" encoded in the bitcode, and return the producer name if any. static Expected readIdentificationBlock(BitstreamCursor &Stream) { if (Error Err = Stream.EnterSubBlock(bitc::IDENTIFICATION_BLOCK_ID)) return std::move(Err); // Read all the records. SmallVector Record; std::string ProducerIdentification; while (true) { BitstreamEntry Entry; if (Expected Res = Stream.advance()) Entry = Res.get(); else return Res.takeError(); switch (Entry.Kind) { default: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ProducerIdentification; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (MaybeBitCode.get()) { default: // Default behavior: reject return error("Invalid value"); case bitc::IDENTIFICATION_CODE_STRING: // IDENTIFICATION: [strchr x N] convertToString(Record, 0, ProducerIdentification); break; case bitc::IDENTIFICATION_CODE_EPOCH: { // EPOCH: [epoch#] unsigned epoch = (unsigned)Record[0]; if (epoch != bitc::BITCODE_CURRENT_EPOCH) { return error( Twine("Incompatible epoch: Bitcode '") + Twine(epoch) + "' vs current: '" + Twine(bitc::BITCODE_CURRENT_EPOCH) + "'"); } } } } } static Expected readIdentificationCode(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { if (Stream.AtEndOfStream()) return ""; BitstreamEntry Entry; if (Expected Res = Stream.advance()) Entry = std::move(Res.get()); else return Res.takeError(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) return readIdentificationBlock(Stream); // Ignore other sub-blocks. if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; case BitstreamEntry::Record: if (Expected Skipped = Stream.skipRecord(Entry.ID)) continue; else return Skipped.takeError(); } } } static Expected hasObjCCategoryInModule(BitstreamCursor &Stream) { if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return std::move(Err); SmallVector Record; // Read all the records for this module. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Check for the i386 and other (x86_64, ARM) conventions if (S.find("__DATA,__objc_catlist") != std::string::npos || S.find("__OBJC,__category") != std::string::npos) return true; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } static Expected hasObjCCategory(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { BitstreamEntry Entry; if (Expected Res = Stream.advance()) Entry = std::move(Res.get()); else return Res.takeError(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return false; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return hasObjCCategoryInModule(Stream); // Ignore other sub-blocks. if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; case BitstreamEntry::Record: if (Expected Skipped = Stream.skipRecord(Entry.ID)) continue; else return Skipped.takeError(); } } } static Expected readModuleTriple(BitstreamCursor &Stream) { if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return std::move(Err); SmallVector Record; std::string Triple; // Read all the records for this module. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Triple; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); Triple = S; break; } } Record.clear(); } llvm_unreachable("Exit infinite loop"); } static Expected readTriple(BitstreamCursor &Stream) { // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return ""; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::MODULE_BLOCK_ID) return readModuleTriple(Stream); // Ignore other sub-blocks. if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; case BitstreamEntry::Record: if (llvm::Expected Skipped = Stream.skipRecord(Entry.ID)) continue; else return Skipped.takeError(); } } } namespace { class BitcodeReaderBase { protected: BitcodeReaderBase(BitstreamCursor Stream, StringRef Strtab) : Stream(std::move(Stream)), Strtab(Strtab) { this->Stream.setBlockInfo(&BlockInfo); } BitstreamBlockInfo BlockInfo; BitstreamCursor Stream; StringRef Strtab; /// In version 2 of the bitcode we store names of global values and comdats in /// a string table rather than in the VST. bool UseStrtab = false; Expected parseVersionRecord(ArrayRef Record); /// If this module uses a string table, pop the reference to the string table /// and return the referenced string and the rest of the record. Otherwise /// just return the record itself. std::pair> readNameFromStrtab(ArrayRef Record); bool readBlockInfo(); // Contains an arbitrary and optional string identifying the bitcode producer std::string ProducerIdentification; Error error(const Twine &Message); }; } // end anonymous namespace Error BitcodeReaderBase::error(const Twine &Message) { std::string FullMsg = Message.str(); if (!ProducerIdentification.empty()) FullMsg += " (Producer: '" + ProducerIdentification + "' Reader: 'LLVM " + LLVM_VERSION_STRING "')"; return ::error(FullMsg); } Expected BitcodeReaderBase::parseVersionRecord(ArrayRef Record) { if (Record.empty()) return error("Invalid record"); unsigned ModuleVersion = Record[0]; if (ModuleVersion > 2) return error("Invalid value"); UseStrtab = ModuleVersion >= 2; return ModuleVersion; } std::pair> BitcodeReaderBase::readNameFromStrtab(ArrayRef Record) { if (!UseStrtab) return {"", Record}; // Invalid reference. Let the caller complain about the record being empty. if (Record[0] + Record[1] > Strtab.size()) return {"", {}}; return {StringRef(Strtab.data() + Record[0], Record[1]), Record.slice(2)}; } namespace { class BitcodeReader : public BitcodeReaderBase, public GVMaterializer { LLVMContext &Context; Module *TheModule = nullptr; // Next offset to start scanning for lazy parsing of function bodies. uint64_t NextUnreadBit = 0; // Last function offset found in the VST. uint64_t LastFunctionBlockBit = 0; bool SeenValueSymbolTable = false; uint64_t VSTOffset = 0; std::vector SectionTable; std::vector GCTable; std::vector TypeList; DenseMap FunctionTypes; BitcodeReaderValueList ValueList; Optional MDLoader; std::vector ComdatList; SmallVector InstructionList; std::vector> GlobalInits; std::vector> IndirectSymbolInits; std::vector> FunctionPrefixes; std::vector> FunctionPrologues; std::vector> FunctionPersonalityFns; /// The set of attributes by index. Index zero in the file is for null, and /// is thus not represented here. As such all indices are off by one. std::vector MAttributes; /// The set of attribute groups. std::map MAttributeGroups; /// While parsing a function body, this is a list of the basic blocks for the /// function. std::vector FunctionBBs; // When reading the module header, this list is populated with functions that // have bodies later in the file. std::vector FunctionsWithBodies; // When intrinsic functions are encountered which require upgrading they are // stored here with their replacement function. using UpdatedIntrinsicMap = DenseMap; UpdatedIntrinsicMap UpgradedIntrinsics; // Intrinsics which were remangled because of types rename UpdatedIntrinsicMap RemangledIntrinsics; // Several operations happen after the module header has been read, but // before function bodies are processed. This keeps track of whether // we've done this yet. bool SeenFirstFunctionBody = false; /// When function bodies are initially scanned, this map contains info about /// where to find deferred function body in the stream. DenseMap DeferredFunctionInfo; /// When Metadata block is initially scanned when parsing the module, we may /// choose to defer parsing of the metadata. This vector contains info about /// which Metadata blocks are deferred. std::vector DeferredMetadataInfo; /// These are basic blocks forward-referenced by block addresses. They are /// inserted lazily into functions when they're loaded. The basic block ID is /// its index into the vector. DenseMap> BasicBlockFwdRefs; std::deque BasicBlockFwdRefQueue; /// Indicates that we are using a new encoding for instruction operands where /// most operands in the current FUNCTION_BLOCK are encoded relative to the /// instruction number, for a more compact encoding. Some instruction /// operands are not relative to the instruction ID: basic block numbers, and /// types. Once the old style function blocks have been phased out, we would /// not need this flag. bool UseRelativeIDs = false; /// True if all functions will be materialized, negating the need to process /// (e.g.) blockaddress forward references. bool WillMaterializeAllForwardRefs = false; bool StripDebugInfo = false; TBAAVerifier TBAAVerifyHelper; std::vector BundleTags; SmallVector SSIDs; public: BitcodeReader(BitstreamCursor Stream, StringRef Strtab, StringRef ProducerIdentification, LLVMContext &Context); Error materializeForwardReferencedFunctions(); Error materialize(GlobalValue *GV) override; Error materializeModule() override; std::vector getIdentifiedStructTypes() const override; /// Main interface to parsing a bitcode buffer. /// \returns true if an error occurred. Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); static uint64_t decodeSignRotatedValue(uint64_t V); /// Materialize any deferred Metadata block. Error materializeMetadata() override; void setStripDebugInfo() override; private: std::vector IdentifiedStructTypes; StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); StructType *createIdentifiedStructType(LLVMContext &Context); /// Map all pointer types within \param Ty to the opaque pointer /// type in the same address space if opaque pointers are being /// used, otherwise nop. This converts a bitcode-reader internal /// type into one suitable for use in a Value. Type *flattenPointerTypes(Type *Ty) { return Ty; } /// Given a fully structured pointer type (i.e. not opaque), return /// the flattened form of its element, suitable for use in a Value. Type *getPointerElementFlatType(Type *Ty) { return flattenPointerTypes(cast(Ty)->getElementType()); } /// Given a fully structured pointer type, get its element type in /// both fully structured form, and flattened form suitable for use /// in a Value. std::pair getPointerElementTypes(Type *FullTy) { Type *ElTy = cast(FullTy)->getElementType(); return std::make_pair(ElTy, flattenPointerTypes(ElTy)); } /// Return the flattened type (suitable for use in a Value) /// specified by the given \param ID. Type *getTypeByID(unsigned ID) { return flattenPointerTypes(getFullyStructuredTypeByID(ID)); } /// Return the fully structured (bitcode-reader internal) type /// corresponding to the given \param ID. Type *getFullyStructuredTypeByID(unsigned ID); Value *getFnValueByID(unsigned ID, Type *Ty, Type **FullTy = nullptr) { if (Ty && Ty->isMetadataTy()) return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); return ValueList.getValueFwdRef(ID, Ty, FullTy); } Metadata *getFnMetadataByID(unsigned ID) { return MDLoader->getMetadataFwdRefOrLoad(ID); } BasicBlock *getBasicBlock(unsigned ID) const { if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID return FunctionBBs[ID]; } AttributeList getAttributes(unsigned i) const { if (i-1 < MAttributes.size()) return MAttributes[i-1]; return AttributeList(); } /// Read a value/type pair out of the specified record from slot 'Slot'. /// Increment Slot past the number of slots used in the record. Return true on /// failure. bool getValueTypePair(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Value *&ResVal, Type **FullTy = nullptr) { if (Slot == Record.size()) return true; unsigned ValNo = (unsigned)Record[Slot++]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; if (ValNo < InstNum) { // If this is not a forward reference, just return the value we already // have. ResVal = getFnValueByID(ValNo, nullptr, FullTy); return ResVal == nullptr; } if (Slot == Record.size()) return true; unsigned TypeNo = (unsigned)Record[Slot++]; ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo)); if (FullTy) *FullTy = getFullyStructuredTypeByID(TypeNo); return ResVal == nullptr; } /// Read a value out of the specified record from slot 'Slot'. Increment Slot /// past the number of slots used by the value in the record. Return true if /// there is an error. bool popValue(SmallVectorImpl &Record, unsigned &Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { if (getValue(Record, Slot, InstNum, Ty, ResVal)) return true; // All values currently take a single record slot. ++Slot; return false; } /// Like popValue, but does not increment the Slot number. bool getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty, Value *&ResVal) { ResVal = getValue(Record, Slot, InstNum, Ty); return ResVal == nullptr; } /// Version of getValue that returns ResVal directly, or 0 if there is an /// error. Value *getValue(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)Record[Slot]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Like getValue, but decodes signed VBRs. Value *getValueSigned(SmallVectorImpl &Record, unsigned Slot, unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)decodeSignRotatedValue(Record[Slot]); // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; return getFnValueByID(ValNo, Ty); } /// Upgrades old-style typeless byval attributes by adding the corresponding /// argument's pointee type. void propagateByValTypes(CallBase *CB, ArrayRef ArgsFullTys); /// Converts alignment exponent (i.e. power of two (or zero)) to the /// corresponding alignment to use. If alignment is too large, returns /// a corresponding error code. Error parseAlignmentValue(uint64_t Exponent, unsigned &Alignment); Error parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind); Error parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata = false); Error parseComdatRecord(ArrayRef Record); Error parseGlobalVarRecord(ArrayRef Record); Error parseFunctionRecord(ArrayRef Record); Error parseGlobalIndirectSymbolRecord(unsigned BitCode, ArrayRef Record); Error parseAttributeBlock(); Error parseAttributeGroupBlock(); Error parseTypeTable(); Error parseTypeTableBody(); Error parseOperandBundleTags(); Error parseSyncScopeNames(); Expected recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT); void setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F, ArrayRef Record); Error parseValueSymbolTable(uint64_t Offset = 0); Error parseGlobalValueSymbolTable(); Error parseConstants(); Error rememberAndSkipFunctionBodies(); Error rememberAndSkipFunctionBody(); /// Save the positions of the Metadata blocks and skip parsing the blocks. Error rememberAndSkipMetadata(); Error typeCheckLoadStoreInst(Type *ValType, Type *PtrType); Error parseFunctionBody(Function *F); Error globalCleanup(); Error resolveGlobalAndIndirectSymbolInits(); Error parseUseLists(); Error findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator); SyncScope::ID getDecodedSyncScopeID(unsigned Val); }; /// Class to manage reading and parsing function summary index bitcode /// files/sections. class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase { /// The module index built during parsing. ModuleSummaryIndex &TheIndex; /// Indicates whether we have encountered a global value summary section /// yet during parsing. bool SeenGlobalValSummary = false; /// Indicates whether we have already parsed the VST, used for error checking. bool SeenValueSymbolTable = false; /// Set to the offset of the VST recorded in the MODULE_CODE_VSTOFFSET record. /// Used to enable on-demand parsing of the VST. uint64_t VSTOffset = 0; // Map to save ValueId to ValueInfo association that was recorded in the // ValueSymbolTable. It is used after the VST is parsed to convert // call graph edges read from the function summary from referencing // callees by their ValueId to using the ValueInfo instead, which is how // they are recorded in the summary index being built. // We save a GUID which refers to the same global as the ValueInfo, but // ignoring the linkage, i.e. for values other than local linkage they are // identical. DenseMap> ValueIdToValueInfoMap; /// Map populated during module path string table parsing, from the /// module ID to a string reference owned by the index's module /// path string table, used to correlate with combined index /// summary records. DenseMap ModuleIdMap; /// Original source file name recorded in a bitcode record. std::string SourceFileName; /// The string identifier given to this module by the client, normally the /// path to the bitcode file. StringRef ModulePath; /// For per-module summary indexes, the unique numerical identifier given to /// this module by the client. unsigned ModuleId; public: ModuleSummaryIndexBitcodeReader(BitstreamCursor Stream, StringRef Strtab, ModuleSummaryIndex &TheIndex, StringRef ModulePath, unsigned ModuleId); Error parseModule(); private: void setValueGUID(uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage, StringRef SourceFileName); Error parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap); std::vector makeRefList(ArrayRef Record); std::vector makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile, bool HasRelBF); Error parseEntireSummary(unsigned ID); Error parseModuleStringTable(); void parseTypeIdCompatibleVtableSummaryRecord(ArrayRef Record); void parseTypeIdCompatibleVtableInfo(ArrayRef Record, size_t &Slot, TypeIdCompatibleVtableInfo &TypeId); std::pair getValueInfoFromValueId(unsigned ValueId); void addThisModule(); ModuleSummaryIndex::ModuleInfo *getThisModule(); }; } // end anonymous namespace BitcodeReader::BitcodeReader(BitstreamCursor Stream, StringRef Strtab, StringRef ProducerIdentification, LLVMContext &Context) : BitcodeReaderBase(std::move(Stream), Strtab), Context(Context), ValueList(Context, Stream.SizeInBytes()) { this->ProducerIdentification = ProducerIdentification; } Error BitcodeReader::materializeForwardReferencedFunctions() { if (WillMaterializeAllForwardRefs) return Error::success(); // Prevent recursion. WillMaterializeAllForwardRefs = true; while (!BasicBlockFwdRefQueue.empty()) { Function *F = BasicBlockFwdRefQueue.front(); BasicBlockFwdRefQueue.pop_front(); IGC_ASSERT(F && "Expected valid function"); if (!BasicBlockFwdRefs.count(F)) // Already materialized. continue; // Check for a function that isn't materializable to prevent an infinite // loop. When parsing a blockaddress stored in a global variable, there // isn't a trivial way to check if a function will have a body without a // linear search through FunctionsWithBodies, so just check it here. if (!F->isMaterializable()) return error("Never resolved function from blockaddress"); // Try to materialize F. if (Error Err = materialize(F)) return Err; } IGC_ASSERT(BasicBlockFwdRefs.empty() && "Function missing from queue"); // Reset state. WillMaterializeAllForwardRefs = false; return Error::success(); } //===----------------------------------------------------------------------===// // Helper functions to implement forward reference resolution, etc. //===----------------------------------------------------------------------===// static bool hasImplicitComdat(size_t Val) { switch (Val) { default: return false; case 1: // Old WeakAnyLinkage case 4: // Old LinkOnceAnyLinkage case 10: // Old WeakODRLinkage case 11: // Old LinkOnceODRLinkage return true; } } static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) { switch (Val) { default: // Map unknown/new linkages to external case 0: return GlobalValue::ExternalLinkage; case 2: return GlobalValue::AppendingLinkage; case 3: return GlobalValue::InternalLinkage; case 5: return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage case 6: return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage case 7: return GlobalValue::ExternalWeakLinkage; case 8: return GlobalValue::CommonLinkage; case 9: return GlobalValue::PrivateLinkage; case 12: return GlobalValue::AvailableExternallyLinkage; case 13: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage case 14: return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateWeakLinkage case 15: return GlobalValue::ExternalLinkage; // Obsolete LinkOnceODRAutoHideLinkage case 1: // Old value with implicit comdat. case 16: return GlobalValue::WeakAnyLinkage; case 10: // Old value with implicit comdat. case 17: return GlobalValue::WeakODRLinkage; case 4: // Old value with implicit comdat. case 18: return GlobalValue::LinkOnceAnyLinkage; case 11: // Old value with implicit comdat. case 19: return GlobalValue::LinkOnceODRLinkage; } } static FunctionSummary::FFlags getDecodedFFlags(uint64_t RawFlags) { FunctionSummary::FFlags Flags; Flags.ReadNone = RawFlags & 0x1; Flags.ReadOnly = (RawFlags >> 1) & 0x1; Flags.NoRecurse = (RawFlags >> 2) & 0x1; Flags.ReturnDoesNotAlias = (RawFlags >> 3) & 0x1; Flags.NoInline = (RawFlags >> 4) & 0x1; return Flags; } /// Decode the flags for GlobalValue in the summary. static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags, uint64_t Version) { // Summary were not emitted before LLVM 3.9, we don't need to upgrade Linkage // like getDecodedLinkage() above. Any future change to the linkage enum and // to getDecodedLinkage() will need to be taken into account here as above. auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits RawFlags = RawFlags >> 4; bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3; // The Live flag wasn't introduced until version 3. For dead stripping // to work correctly on earlier versions, we must conservatively treat all // values as live. bool Live = (RawFlags & 0x2) || Version < 3; bool Local = (RawFlags & 0x4); bool AutoHide = (RawFlags & 0x8); return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live, Local, AutoHide); } // Decode the flags for GlobalVariable in the summary static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) { return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false, (RawFlags & 0x2) ? true : false); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { switch (Val) { default: // Map unknown visibilities to default. case 0: return GlobalValue::DefaultVisibility; case 1: return GlobalValue::HiddenVisibility; case 2: return GlobalValue::ProtectedVisibility; } } static GlobalValue::DLLStorageClassTypes getDecodedDLLStorageClass(unsigned Val) { switch (Val) { default: // Map unknown values to default. case 0: return GlobalValue::DefaultStorageClass; case 1: return GlobalValue::DLLImportStorageClass; case 2: return GlobalValue::DLLExportStorageClass; } } static bool getDecodedDSOLocal(unsigned Val) { switch(Val) { default: // Map unknown values to preemptable. case 0: return false; case 1: return true; } } static GlobalVariable::ThreadLocalMode getDecodedThreadLocalMode(unsigned Val) { switch (Val) { case 0: return GlobalVariable::NotThreadLocal; default: // Map unknown non-zero value to general dynamic. case 1: return GlobalVariable::GeneralDynamicTLSModel; case 2: return GlobalVariable::LocalDynamicTLSModel; case 3: return GlobalVariable::InitialExecTLSModel; case 4: return GlobalVariable::LocalExecTLSModel; } } static GlobalVariable::UnnamedAddr getDecodedUnnamedAddrType(unsigned Val) { switch (Val) { default: // Map unknown to UnnamedAddr::None. case 0: return GlobalVariable::UnnamedAddr::None; case 1: return GlobalVariable::UnnamedAddr::Global; case 2: return GlobalVariable::UnnamedAddr::Local; } } static int getDecodedCastOpcode(unsigned Val) { switch (Val) { default: return -1; case bitc::CAST_TRUNC : return Instruction::Trunc; case bitc::CAST_ZEXT : return Instruction::ZExt; case bitc::CAST_SEXT : return Instruction::SExt; case bitc::CAST_FPTOUI : return Instruction::FPToUI; case bitc::CAST_FPTOSI : return Instruction::FPToSI; case bitc::CAST_UITOFP : return Instruction::UIToFP; case bitc::CAST_SITOFP : return Instruction::SIToFP; case bitc::CAST_FPTRUNC : return Instruction::FPTrunc; case bitc::CAST_FPEXT : return Instruction::FPExt; case bitc::CAST_PTRTOINT: return Instruction::PtrToInt; case bitc::CAST_INTTOPTR: return Instruction::IntToPtr; case bitc::CAST_BITCAST : return Instruction::BitCast; case bitc::CAST_ADDRSPACECAST: return Instruction::AddrSpaceCast; } } static int getDecodedUnaryOpcode(unsigned Val, Type *Ty) { bool IsFP = Ty->isFPOrFPVectorTy(); // UnOps are only valid for int/fp or vector of int/fp types if (!IsFP && !Ty->isIntOrIntVectorTy()) return -1; switch (Val) { default: return -1; case bitc::UNOP_NEG: return IsFP ? Instruction::FNeg : -1; } } static int getDecodedBinaryOpcode(unsigned Val, Type *Ty) { bool IsFP = Ty->isFPOrFPVectorTy(); // BinOps are only valid for int/fp or vector of int/fp types if (!IsFP && !Ty->isIntOrIntVectorTy()) return -1; switch (Val) { default: return -1; case bitc::BINOP_ADD: return IsFP ? Instruction::FAdd : Instruction::Add; case bitc::BINOP_SUB: return IsFP ? Instruction::FSub : Instruction::Sub; case bitc::BINOP_MUL: return IsFP ? Instruction::FMul : Instruction::Mul; case bitc::BINOP_UDIV: return IsFP ? -1 : Instruction::UDiv; case bitc::BINOP_SDIV: return IsFP ? Instruction::FDiv : Instruction::SDiv; case bitc::BINOP_UREM: return IsFP ? -1 : Instruction::URem; case bitc::BINOP_SREM: return IsFP ? Instruction::FRem : Instruction::SRem; case bitc::BINOP_SHL: return IsFP ? -1 : Instruction::Shl; case bitc::BINOP_LSHR: return IsFP ? -1 : Instruction::LShr; case bitc::BINOP_ASHR: return IsFP ? -1 : Instruction::AShr; case bitc::BINOP_AND: return IsFP ? -1 : Instruction::And; case bitc::BINOP_OR: return IsFP ? -1 : Instruction::Or; case bitc::BINOP_XOR: return IsFP ? -1 : Instruction::Xor; } } static AtomicRMWInst::BinOp getDecodedRMWOperation(unsigned Val) { switch (Val) { default: return AtomicRMWInst::BAD_BINOP; case bitc::RMW_XCHG: return AtomicRMWInst::Xchg; case bitc::RMW_ADD: return AtomicRMWInst::Add; case bitc::RMW_SUB: return AtomicRMWInst::Sub; case bitc::RMW_AND: return AtomicRMWInst::And; case bitc::RMW_NAND: return AtomicRMWInst::Nand; case bitc::RMW_OR: return AtomicRMWInst::Or; case bitc::RMW_XOR: return AtomicRMWInst::Xor; case bitc::RMW_MAX: return AtomicRMWInst::Max; case bitc::RMW_MIN: return AtomicRMWInst::Min; case bitc::RMW_UMAX: return AtomicRMWInst::UMax; case bitc::RMW_UMIN: return AtomicRMWInst::UMin; case bitc::RMW_FADD: return AtomicRMWInst::FAdd; case bitc::RMW_FSUB: return AtomicRMWInst::FSub; } } static AtomicOrdering getDecodedOrdering(unsigned Val) { switch (Val) { case bitc::ORDERING_NOTATOMIC: return AtomicOrdering::NotAtomic; case bitc::ORDERING_UNORDERED: return AtomicOrdering::Unordered; case bitc::ORDERING_MONOTONIC: return AtomicOrdering::Monotonic; case bitc::ORDERING_ACQUIRE: return AtomicOrdering::Acquire; case bitc::ORDERING_RELEASE: return AtomicOrdering::Release; case bitc::ORDERING_ACQREL: return AtomicOrdering::AcquireRelease; default: // Map unknown orderings to sequentially-consistent. case bitc::ORDERING_SEQCST: return AtomicOrdering::SequentiallyConsistent; } } static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) { switch (Val) { default: // Map unknown selection kinds to any. case bitc::COMDAT_SELECTION_KIND_ANY: return Comdat::Any; case bitc::COMDAT_SELECTION_KIND_EXACT_MATCH: return Comdat::ExactMatch; case bitc::COMDAT_SELECTION_KIND_LARGEST: return Comdat::Largest; case bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES: return Comdat::NoDuplicates; case bitc::COMDAT_SELECTION_KIND_SAME_SIZE: return Comdat::SameSize; } } static FastMathFlags getDecodedFastMathFlags(unsigned Val) { FastMathFlags FMF; if (0 != (Val & bitc::UnsafeAlgebra)) FMF.setFast(); if (0 != (Val & bitc::AllowReassoc)) FMF.setAllowReassoc(); if (0 != (Val & bitc::NoNaNs)) FMF.setNoNaNs(); if (0 != (Val & bitc::NoInfs)) FMF.setNoInfs(); if (0 != (Val & bitc::NoSignedZeros)) FMF.setNoSignedZeros(); if (0 != (Val & bitc::AllowReciprocal)) FMF.setAllowReciprocal(); if (0 != (Val & bitc::AllowContract)) FMF.setAllowContract(true); if (0 != (Val & bitc::ApproxFunc)) FMF.setApproxFunc(); return FMF; } static void upgradeDLLImportExportLinkage(GlobalValue *GV, unsigned Val) { switch (Val) { case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break; case 6: GV->setDLLStorageClass(GlobalValue::DLLExportStorageClass); break; } } Type *BitcodeReader::getFullyStructuredTypeByID(unsigned ID) { // The type table size is always specified correctly. if (ID >= TypeList.size()) return nullptr; if (Type *Ty = TypeList[ID]) return Ty; // If we have a forward reference, the only possible case is when it is to a // named struct. Just create a placeholder for now. return TypeList[ID] = createIdentifiedStructType(Context); } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context, StringRef Name) { auto *Ret = StructType::create(Context, Name); IdentifiedStructTypes.push_back(Ret); return Ret; } StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) { auto *Ret = StructType::create(Context); IdentifiedStructTypes.push_back(Ret); return Ret; } //===----------------------------------------------------------------------===// // Functions for parsing blocks from the bitcode file //===----------------------------------------------------------------------===// static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { switch (Val) { case Attribute::EndAttrKinds: llvm_unreachable("Synthetic enumerators which should never get here"); case Attribute::None: return 0; case Attribute::ZExt: return 1 << 0; case Attribute::SExt: return 1 << 1; case Attribute::NoReturn: return 1 << 2; case Attribute::InReg: return 1 << 3; case Attribute::StructRet: return 1 << 4; case Attribute::NoUnwind: return 1 << 5; case Attribute::NoAlias: return 1 << 6; case Attribute::ByVal: return 1 << 7; case Attribute::Nest: return 1 << 8; case Attribute::ReadNone: return 1 << 9; case Attribute::ReadOnly: return 1 << 10; case Attribute::NoInline: return 1 << 11; case Attribute::AlwaysInline: return 1 << 12; case Attribute::OptimizeForSize: return 1 << 13; case Attribute::StackProtect: return 1 << 14; case Attribute::StackProtectReq: return 1 << 15; case Attribute::Alignment: return 31 << 16; case Attribute::NoCapture: return 1 << 21; case Attribute::NoRedZone: return 1 << 22; case Attribute::NoImplicitFloat: return 1 << 23; case Attribute::Naked: return 1 << 24; case Attribute::InlineHint: return 1 << 25; case Attribute::StackAlignment: return 7 << 26; case Attribute::ReturnsTwice: return 1 << 29; case Attribute::UWTable: return 1 << 30; case Attribute::NonLazyBind: return 1U << 31; case Attribute::SanitizeAddress: return 1ULL << 32; case Attribute::MinSize: return 1ULL << 33; case Attribute::NoDuplicate: return 1ULL << 34; case Attribute::StackProtectStrong: return 1ULL << 35; case Attribute::SanitizeThread: return 1ULL << 36; case Attribute::SanitizeMemory: return 1ULL << 37; case Attribute::NoBuiltin: return 1ULL << 38; case Attribute::Returned: return 1ULL << 39; case Attribute::Cold: return 1ULL << 40; case Attribute::Builtin: return 1ULL << 41; case Attribute::OptimizeNone: return 1ULL << 42; case Attribute::InAlloca: return 1ULL << 43; case Attribute::NonNull: return 1ULL << 44; case Attribute::JumpTable: return 1ULL << 45; case Attribute::Convergent: return 1ULL << 46; case Attribute::SafeStack: return 1ULL << 47; case Attribute::NoRecurse: return 1ULL << 48; case Attribute::InaccessibleMemOnly: return 1ULL << 49; case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50; case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; case Attribute::WriteOnly: return 1ULL << 53; case Attribute::Speculatable: return 1ULL << 54; case Attribute::StrictFP: return 1ULL << 55; case Attribute::SanitizeHWAddress: return 1ULL << 56; case Attribute::NoCfCheck: return 1ULL << 57; case Attribute::OptForFuzzing: return 1ULL << 58; case Attribute::ShadowCallStack: return 1ULL << 59; case Attribute::SpeculativeLoadHardening: return 1ULL << 60; case Attribute::ImmArg: return 1ULL << 61; case Attribute::WillReturn: return 1ULL << 62; case Attribute::NoFree: return 1ULL << 63; case Attribute::NoSync: llvm_unreachable("nosync attribute not supported in raw format"); break; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; case Attribute::DereferenceableOrNull: llvm_unreachable("dereferenceable_or_null attribute not supported in raw " "format"); break; case Attribute::ArgMemOnly: llvm_unreachable("argmemonly attribute not supported in raw format"); break; case Attribute::AllocSize: llvm_unreachable("allocsize not supported in raw format"); break; case Attribute::SanitizeMemTag: llvm_unreachable("sanitize_memtag attribute not supported in raw format"); break; default: llvm_unreachable("Unsupported attribute type"); //return 0; } } static void addRawAttributeValue(AttrBuilder &B, uint64_t Val) { if (!Val) return; for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; I = Attribute::AttrKind(I + 1)) { if (I == Attribute::SanitizeMemTag || I == Attribute::Dereferenceable || I == Attribute::DereferenceableOrNull || I == Attribute::ArgMemOnly || I == Attribute::AllocSize || I == Attribute::NoSync) continue; if (uint64_t A = (Val & getRawAttributeMask(I))) { if (I == Attribute::Alignment) B.addAlignmentAttr(1ULL << ((A >> 16) - 1)); else if (I == Attribute::StackAlignment) B.addStackAlignmentAttr(1ULL << ((A >> 26)-1)); else B.addAttribute(I); } } } /// This fills an AttrBuilder object with the LLVM attributes that have /// been decoded from the given integer. This function must stay in sync with /// 'encodeLLVMAttributesForBitcode'. static void decodeLLVMAttributesForBitcode(AttrBuilder &B, uint64_t EncodedAttrs) { // FIXME: Remove in 4.0. // The alignment is stored as a 16-bit raw value from bits 31--16. We shift // the bits above 31 down by 11 bits. unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; IGC_ASSERT((!Alignment || isPowerOf2_32(Alignment)) && "Alignment must be a power of two."); if (Alignment) B.addAlignmentAttr(Alignment); addRawAttributeValue(B, ((EncodedAttrs & (0xfffffULL << 32)) >> 11) | (EncodedAttrs & 0xffff)); } Error BitcodeReader::parseAttributeBlock() { if (Error Err = Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID)) return Err; if (!MAttributes.empty()) return error("Invalid multiple blocks"); SmallVector Record; SmallVector Attrs; // Read all the records. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_CODE_ENTRY_OLD: // ENTRY: [paramidx0, attr0, ...] // FIXME: Remove in 4.0. if (Record.size() & 1) return error("Invalid record"); for (unsigned i = 0, e = Record.size(); i != e; i += 2) { AttrBuilder B; decodeLLVMAttributesForBitcode(B, Record[i+1]); Attrs.push_back(AttributeList::get(Context, Record[i], B)); } MAttributes.push_back(AttributeList::get(Context, Attrs)); Attrs.clear(); break; case bitc::PARAMATTR_CODE_ENTRY: // ENTRY: [attrgrp0, attrgrp1, ...] for (unsigned i = 0, e = Record.size(); i != e; ++i) Attrs.push_back(MAttributeGroups[Record[i]]); MAttributes.push_back(AttributeList::get(Context, Attrs)); Attrs.clear(); break; } } } // Returns Attribute::None on unrecognized codes. static Attribute::AttrKind getAttrFromCode(uint64_t Code) { switch (Code) { default: return Attribute::None; case bitc::ATTR_KIND_ALIGNMENT: return Attribute::Alignment; case bitc::ATTR_KIND_ALWAYS_INLINE: return Attribute::AlwaysInline; case bitc::ATTR_KIND_ARGMEMONLY: return Attribute::ArgMemOnly; case bitc::ATTR_KIND_BUILTIN: return Attribute::Builtin; case bitc::ATTR_KIND_BY_VAL: return Attribute::ByVal; case bitc::ATTR_KIND_IN_ALLOCA: return Attribute::InAlloca; case bitc::ATTR_KIND_COLD: return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: return Attribute::InaccessibleMemOnly; case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: return Attribute::InaccessibleMemOrArgMemOnly; case bitc::ATTR_KIND_INLINE_HINT: return Attribute::InlineHint; case bitc::ATTR_KIND_IN_REG: return Attribute::InReg; case bitc::ATTR_KIND_JUMP_TABLE: return Attribute::JumpTable; case bitc::ATTR_KIND_MIN_SIZE: return Attribute::MinSize; case bitc::ATTR_KIND_NAKED: return Attribute::Naked; case bitc::ATTR_KIND_NEST: return Attribute::Nest; case bitc::ATTR_KIND_NO_ALIAS: return Attribute::NoAlias; case bitc::ATTR_KIND_NO_BUILTIN: return Attribute::NoBuiltin; case bitc::ATTR_KIND_NO_CAPTURE: return Attribute::NoCapture; case bitc::ATTR_KIND_NO_DUPLICATE: return Attribute::NoDuplicate; case bitc::ATTR_KIND_NOFREE: return Attribute::NoFree; case bitc::ATTR_KIND_NO_IMPLICIT_FLOAT: return Attribute::NoImplicitFloat; case bitc::ATTR_KIND_NO_INLINE: return Attribute::NoInline; case bitc::ATTR_KIND_NO_RECURSE: return Attribute::NoRecurse; case bitc::ATTR_KIND_NON_LAZY_BIND: return Attribute::NonLazyBind; case bitc::ATTR_KIND_NON_NULL: return Attribute::NonNull; case bitc::ATTR_KIND_DEREFERENCEABLE: return Attribute::Dereferenceable; case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: return Attribute::DereferenceableOrNull; case bitc::ATTR_KIND_ALLOC_SIZE: return Attribute::AllocSize; case bitc::ATTR_KIND_NO_RED_ZONE: return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: return Attribute::NoReturn; case bitc::ATTR_KIND_NOSYNC: return Attribute::NoSync; case bitc::ATTR_KIND_NOCF_CHECK: return Attribute::NoCfCheck; case bitc::ATTR_KIND_NO_UNWIND: return Attribute::NoUnwind; case bitc::ATTR_KIND_OPT_FOR_FUZZING: return Attribute::OptForFuzzing; case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: return Attribute::OptimizeForSize; case bitc::ATTR_KIND_OPTIMIZE_NONE: return Attribute::OptimizeNone; case bitc::ATTR_KIND_READ_NONE: return Attribute::ReadNone; case bitc::ATTR_KIND_READ_ONLY: return Attribute::ReadOnly; case bitc::ATTR_KIND_RETURNED: return Attribute::Returned; case bitc::ATTR_KIND_RETURNS_TWICE: return Attribute::ReturnsTwice; case bitc::ATTR_KIND_S_EXT: return Attribute::SExt; case bitc::ATTR_KIND_SPECULATABLE: return Attribute::Speculatable; case bitc::ATTR_KIND_STACK_ALIGNMENT: return Attribute::StackAlignment; case bitc::ATTR_KIND_STACK_PROTECT: return Attribute::StackProtect; case bitc::ATTR_KIND_STACK_PROTECT_REQ: return Attribute::StackProtectReq; case bitc::ATTR_KIND_STACK_PROTECT_STRONG: return Attribute::StackProtectStrong; case bitc::ATTR_KIND_SAFESTACK: return Attribute::SafeStack; case bitc::ATTR_KIND_SHADOWCALLSTACK: return Attribute::ShadowCallStack; case bitc::ATTR_KIND_STRICT_FP: return Attribute::StrictFP; case bitc::ATTR_KIND_STRUCT_RET: return Attribute::StructRet; case bitc::ATTR_KIND_SANITIZE_ADDRESS: return Attribute::SanitizeAddress; case bitc::ATTR_KIND_SANITIZE_HWADDRESS: return Attribute::SanitizeHWAddress; case bitc::ATTR_KIND_SANITIZE_THREAD: return Attribute::SanitizeThread; case bitc::ATTR_KIND_SANITIZE_MEMORY: return Attribute::SanitizeMemory; case bitc::ATTR_KIND_SPECULATIVE_LOAD_HARDENING: return Attribute::SpeculativeLoadHardening; case bitc::ATTR_KIND_SWIFT_ERROR: return Attribute::SwiftError; case bitc::ATTR_KIND_SWIFT_SELF: return Attribute::SwiftSelf; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; case bitc::ATTR_KIND_WILLRETURN: return Attribute::WillReturn; case bitc::ATTR_KIND_WRITEONLY: return Attribute::WriteOnly; case bitc::ATTR_KIND_Z_EXT: return Attribute::ZExt; case bitc::ATTR_KIND_IMMARG: return Attribute::ImmArg; case bitc::ATTR_KIND_SANITIZE_MEMTAG: return Attribute::SanitizeMemTag; } } Error BitcodeReader::parseAlignmentValue(uint64_t Exponent, unsigned &Alignment) { // Note: Alignment in bitcode files is incremented by 1, so that zero // can be used for default alignment. if (Exponent > Value::MaxAlignmentExponent + 1) return error("Invalid alignment value"); Alignment = (1 << static_cast(Exponent)) >> 1; return Error::success(); } Error BitcodeReader::parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind) { *Kind = getAttrFromCode(Code); if (*Kind == Attribute::None) return error("Unknown attribute kind (" + Twine(Code) + ")"); return Error::success(); } Error BitcodeReader::parseAttributeGroupBlock() { if (Error Err = Stream.EnterSubBlock(bitc::PARAMATTR_GROUP_BLOCK_ID)) return Err; if (!MAttributeGroups.empty()) return error("Invalid multiple blocks"); SmallVector Record; // Read all the records. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; case bitc::PARAMATTR_GRP_CODE_ENTRY: { // ENTRY: [grpid, idx, a0, a1, ...] if (Record.size() < 3) return error("Invalid record"); uint64_t GrpID = Record[0]; uint64_t Idx = Record[1]; // Index of the object this attribute refers to. AttrBuilder B; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Record[i] == 0) { // Enum attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; // Upgrade old-style byval attribute to one with a type, even if it's // nullptr. We will have to insert the real type when we associate // this AttributeList with a function. if (Kind == Attribute::ByVal) B.addByValAttr(nullptr); B.addAttribute(Kind); } else if (Record[i] == 1) { // Integer attribute Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; if (Kind == Attribute::Alignment) B.addAlignmentAttr(Record[++i]); else if (Kind == Attribute::StackAlignment) B.addStackAlignmentAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); else if (Kind == Attribute::DereferenceableOrNull) B.addDereferenceableOrNullAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); } else if (Record[i] == 3 || Record[i] == 4) { // String attribute bool HasValue = (Record[i++] == 4); SmallString<64> KindStr; SmallString<64> ValStr; while (Record[i] != 0 && i != e) KindStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Kind string not null terminated"); if (HasValue) { // Has a value associated with it. ++i; // Skip the '0' that terminates the "kind" string. while (Record[i] != 0 && i != e) ValStr += Record[i++]; IGC_ASSERT(Record[i] == 0 && "Value string not null terminated"); } B.addAttribute(KindStr.str(), ValStr.str()); } else { IGC_ASSERT((Record[i] == 5 || Record[i] == 6) && "Invalid attribute group entry"); bool HasType = Record[i] == 6; Attribute::AttrKind Kind; if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; if (Kind == Attribute::ByVal) B.addByValAttr(HasType ? getTypeByID(Record[++i]) : nullptr); } } MAttributeGroups[GrpID] = AttributeList::get(Context, Idx, B); break; } } } } Error BitcodeReader::parseTypeTable() { if (Error Err = Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW)) return Err; return parseTypeTableBody(); } Error BitcodeReader::parseTypeTableBody() { if (!TypeList.empty()) return error("Invalid multiple blocks"); SmallVector Record; unsigned NumRecords = 0; SmallString<64> TypeName; // Read all the records for this type table. while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NumRecords != TypeList.size()) return error("Malformed block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *ResultTy = nullptr; Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: return error("Invalid value"); case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] // TYPE_CODE_NUMENTRY contains a count of the number of types in the // type list. This allows us to reserve space. if (Record.size() < 1) return error("Invalid record"); TypeList.resize(Record[0]); continue; case bitc::TYPE_CODE_VOID: // VOID ResultTy = Type::getVoidTy(Context); break; case bitc::TYPE_CODE_HALF: // HALF ResultTy = Type::getHalfTy(Context); break; case bitc::TYPE_CODE_FLOAT: // FLOAT ResultTy = Type::getFloatTy(Context); break; case bitc::TYPE_CODE_DOUBLE: // DOUBLE ResultTy = Type::getDoubleTy(Context); break; case bitc::TYPE_CODE_X86_FP80: // X86_FP80 ResultTy = Type::getX86_FP80Ty(Context); break; case bitc::TYPE_CODE_FP128: // FP128 ResultTy = Type::getFP128Ty(Context); break; case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 ResultTy = Type::getPPC_FP128Ty(Context); break; case bitc::TYPE_CODE_LABEL: // LABEL ResultTy = Type::getLabelTy(Context); break; case bitc::TYPE_CODE_METADATA: // METADATA ResultTy = Type::getMetadataTy(Context); break; case bitc::TYPE_CODE_X86_MMX: // X86_MMX ResultTy = Type::getX86_MMXTy(Context); break; case bitc::TYPE_CODE_TOKEN: // TOKEN ResultTy = Type::getTokenTy(Context); break; case bitc::TYPE_CODE_INTEGER: { // INTEGER: [width] if (Record.size() < 1) return error("Invalid record"); uint64_t NumBits = Record[0]; if (NumBits < IntegerType::MIN_INT_BITS || NumBits > IntegerType::MAX_INT_BITS) return error("Bitwidth for integer type out of range"); ResultTy = IntegerType::get(Context, NumBits); break; } case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or // [pointee type, address space] if (Record.size() < 1) return error("Invalid record"); unsigned AddressSpace = 0; if (Record.size() == 2) AddressSpace = Record[1]; ResultTy = getTypeByID(Record[0]); if (!ResultTy || !PointerType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = PointerType::get(ResultTy, AddressSpace); break; } case bitc::TYPE_CODE_FUNCTION_OLD: { // FIXME: attrid is dead, remove it in LLVM 4.0 // FUNCTION: [vararg, attrid, retty, paramty x N] if (Record.size() < 3) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 3, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) ArgTys.push_back(T); else break; } ResultTy = getTypeByID(Record[2]); if (!ResultTy || ArgTys.size() < Record.size()-3) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_FUNCTION: { // FUNCTION: [vararg, retty, paramty x N] if (Record.size() < 2) return error("Invalid record"); SmallVector ArgTys; for (unsigned i = 2, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) { if (!FunctionType::isValidArgumentType(T)) return error("Invalid function argument type"); ArgTys.push_back(T); } else break; } ResultTy = getTypeByID(Record[1]); if (!ResultTy || ArgTys.size() < Record.size()-2) return error("Invalid type"); ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid type"); ResultTy = StructType::get(Context, EltTys, Record[0]); break; } case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N] if (convertToString(Record, 0, TypeName)) return error("Invalid record"); continue; case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N] if (Record.size() < 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); SmallVector EltTys; for (unsigned i = 1, e = Record.size(); i != e; ++i) { if (Type *T = getTypeByID(Record[i])) EltTys.push_back(T); else break; } if (EltTys.size() != Record.size()-1) return error("Invalid record"); Res->setBody(EltTys, Record[0]); ResultTy = Res; break; } case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: [] if (Record.size() != 1) return error("Invalid record"); if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); // Check to see if this was forward referenced, if so fill in the temp. StructType *Res = cast_or_null(TypeList[NumRecords]); if (Res) { Res->setName(TypeName); TypeList[NumRecords] = nullptr; } else // Otherwise, create a new struct with no body. Res = createIdentifiedStructType(Context, TypeName); TypeName.clear(); ResultTy = Res; break; } case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !ArrayType::isValidElementType(ResultTy)) return error("Invalid type"); ResultTy = ArrayType::get(ResultTy, Record[0]); break; case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] if (Record.size() < 2) return error("Invalid record"); if (Record[0] == 0) return error("Invalid vector length"); ResultTy = getTypeByID(Record[1]); if (!ResultTy || !StructType::isValidElementType(ResultTy)) return error("Invalid type"); bool Scalable = Record.size() > 2 ? Record[2] : false; ResultTy = VectorType::get(ResultTy, Record[0], Scalable); break; } if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); if (TypeList[NumRecords]) return error( "Invalid TYPE table: Only named structs can be forward referenced"); IGC_ASSERT(ResultTy && "Didn't read a type?"); TypeList[NumRecords++] = ResultTy; } } Error BitcodeReader::parseOperandBundleTags() { if (Error Err = Stream.EnterSubBlock(bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID)) return Err; if (!BundleTags.empty()) return error("Invalid multiple blocks"); SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Tags are implicitly mapped to integers by their order. Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); if (MaybeRecord.get() != bitc::OPERAND_BUNDLE_TAG) return error("Invalid record"); // OPERAND_BUNDLE_TAG: [strchr x N] BundleTags.emplace_back(); if (convertToString(Record, 0, BundleTags.back())) return error("Invalid record"); Record.clear(); } } Error BitcodeReader::parseSyncScopeNames() { if (Error Err = Stream.EnterSubBlock(bitc::SYNC_SCOPE_NAMES_BLOCK_ID)) return Err; if (!SSIDs.empty()) return error("Invalid multiple synchronization scope names blocks"); SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (SSIDs.empty()) return error("Invalid empty synchronization scope names block"); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Synchronization scope names are implicitly mapped to synchronization // scope IDs by their order. Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); if (MaybeRecord.get() != bitc::SYNC_SCOPE_NAME) return error("Invalid record"); SmallString<16> SSN; if (convertToString(Record, 0, SSN)) return error("Invalid record"); SSIDs.push_back(Context.getOrInsertSyncScopeID(SSN)); Record.clear(); } } /// Associate a value with its name from the given index in the provided record. Expected BitcodeReader::recordValue(SmallVectorImpl &Record, unsigned NameIndex, Triple &TT) { SmallString<128> ValueName; if (convertToString(Record, NameIndex, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; if (ValueID >= ValueList.size() || !ValueList[ValueID]) return error("Invalid record"); Value *V = ValueList[ValueID]; StringRef NameStr(ValueName.data(), ValueName.size()); if (NameStr.find_first_of(0) != StringRef::npos) return error("Invalid value name"); V->setName(NameStr); auto *GO = dyn_cast(V); if (GO) { if (GO->getComdat() == reinterpret_cast(1)) { if (TT.supportsCOMDAT()) GO->setComdat(TheModule->getOrInsertComdat(V->getName())); else GO->setComdat(nullptr); } } return V; } /// Helper to note and return the current location, and jump to the given /// offset. static Expected jumpToValueSymbolTable(uint64_t Offset, BitstreamCursor &Stream) { // Save the current parsing location so we can jump back at the end // of the VST read. uint64_t CurrentBit = Stream.GetCurrentBitNo(); if (Error JumpFailed = Stream.JumpToBit(Offset * 32)) return std::move(JumpFailed); Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); IGC_ASSERT(MaybeEntry.get().Kind == BitstreamEntry::SubBlock); IGC_ASSERT(MaybeEntry.get().ID == bitc::VALUE_SYMTAB_BLOCK_ID); return CurrentBit; } void BitcodeReader::setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F, ArrayRef Record) { // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. uint64_t FuncWordOffset = Record[1] - 1; uint64_t FuncBitOffset = FuncWordOffset * 32; DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta; // Set the LastFunctionBlockBit to point to the last function block. // Later when parsing is resumed after function materialization, // we can simply skip that last function block. if (FuncBitOffset > LastFunctionBlockBit) LastFunctionBlockBit = FuncBitOffset; } /// Read a new-style GlobalValue symbol table. Error BitcodeReader::parseGlobalValueSymbolTable() { unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Error Err = Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return Err; SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: break; } Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { case bitc::VST_CODE_FNENTRY: // [valueid, offset] setDeferredFunctionInfo(FuncBitcodeOffsetDelta, cast(ValueList[Record[0]]), Record); break; } } } /// Parse the value symbol table at either the current parsing location or /// at the given bit offset if provided. Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) { uint64_t CurrentBit; // Pass in the Offset to distinguish between calling for the module-level // VST (where we want to jump to the VST offset) and the function-level // VST (where we don't). if (Offset > 0) { Expected MaybeCurrentBit = jumpToValueSymbolTable(Offset, Stream); if (!MaybeCurrentBit) return MaybeCurrentBit.takeError(); CurrentBit = MaybeCurrentBit.get(); // If this module uses a string table, read this as a module-level VST. if (UseStrtab) { if (Error Err = parseGlobalValueSymbolTable()) return Err; if (Error JumpFailed = Stream.JumpToBit(CurrentBit)) return JumpFailed; return Error::success(); } // Otherwise, the VST will be in a similar format to a function-level VST, // and will contain symbol names. } // Compute the delta between the bitcode indices in the VST (the word offset // to the word-aligned ENTER_SUBBLOCK for the function block, and that // expected by the lazy reader. The reader's EnterSubBlock expects to have // already read the ENTER_SUBBLOCK code (size getAbbrevIDWidth) and BlockID // (size BlockIDWidth). Note that we access the stream's AbbrevID width here // just before entering the VST subblock because: 1) the EnterSubBlock // changes the AbbrevID width; 2) the VST block is nested within the same // outer MODULE_BLOCK as the FUNCTION_BLOCKs and therefore have the same // AbbrevID width before calling EnterSubBlock; and 3) when we want to // jump to the FUNCTION_BLOCK using this offset later, we don't want // to rely on the stream's AbbrevID width being that of the MODULE_BLOCK. unsigned FuncBitcodeOffsetDelta = Stream.getAbbrevIDWidth() + bitc::BlockIDWidth; if (Error Err = Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return Err; SmallVector Record; Triple TT(TheModule->getTargetTriple()); // Read all the records for this value table. SmallString<128> ValueName; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (Offset > 0) if (Error JumpFailed = Stream.JumpToBit(CurrentBit)) return JumpFailed; return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: unknown type. break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] Expected ValOrErr = recordValue(Record, 1, TT); if (Error Err = ValOrErr.takeError()) return Err; ValOrErr.get(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] Expected ValOrErr = recordValue(Record, 2, TT); if (Error Err = ValOrErr.takeError()) return Err; Value *V = ValOrErr.get(); // Ignore function offsets emitted for aliases of functions in older // versions of LLVM. if (auto *F = dyn_cast(V)) setDeferredFunctionInfo(FuncBitcodeOffsetDelta, F, Record); break; } case bitc::VST_CODE_BBENTRY: { if (convertToString(Record, 1, ValueName)) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[0]); if (!BB) return error("Invalid record"); BB->setName(StringRef(ValueName.data(), ValueName.size())); ValueName.clear(); break; } } } } /// Decode a signed value stored with the sign bit in the LSB for dense VBR /// encoding. uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) { if ((V & 1) == 0) return V >> 1; if (V != 1) return -(V >> 1); // There is no such thing as -0 with integers. "-0" really means MININT. return 1ULL << 63; } /// Resolve all of the initializers for global values and aliases that we can. Error BitcodeReader::resolveGlobalAndIndirectSymbolInits() { std::vector> GlobalInitWorklist; std::vector> IndirectSymbolInitWorklist; std::vector> FunctionPrefixWorklist; std::vector> FunctionPrologueWorklist; std::vector> FunctionPersonalityFnWorklist; GlobalInitWorklist.swap(GlobalInits); IndirectSymbolInitWorklist.swap(IndirectSymbolInits); FunctionPrefixWorklist.swap(FunctionPrefixes); FunctionPrologueWorklist.swap(FunctionPrologues); FunctionPersonalityFnWorklist.swap(FunctionPersonalityFns); while (!GlobalInitWorklist.empty()) { unsigned ValID = GlobalInitWorklist.back().second; if (ValID >= ValueList.size()) { // Not ready to resolve this yet, it requires something later in the file. GlobalInits.push_back(GlobalInitWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) GlobalInitWorklist.back().first->setInitializer(C); else return error("Expected a constant"); } GlobalInitWorklist.pop_back(); } while (!IndirectSymbolInitWorklist.empty()) { unsigned ValID = IndirectSymbolInitWorklist.back().second; if (ValID >= ValueList.size()) { IndirectSymbolInits.push_back(IndirectSymbolInitWorklist.back()); } else { Constant *C = dyn_cast_or_null(ValueList[ValID]); if (!C) return error("Expected a constant"); GlobalIndirectSymbol *GIS = IndirectSymbolInitWorklist.back().first; if (isa(GIS) && C->getType() != GIS->getType()) return error("Alias and aliasee types don't match"); GIS->setIndirectSymbol(C); } IndirectSymbolInitWorklist.pop_back(); } while (!FunctionPrefixWorklist.empty()) { unsigned ValID = FunctionPrefixWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrefixes.push_back(FunctionPrefixWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrefixWorklist.back().first->setPrefixData(C); else return error("Expected a constant"); } FunctionPrefixWorklist.pop_back(); } while (!FunctionPrologueWorklist.empty()) { unsigned ValID = FunctionPrologueWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPrologues.push_back(FunctionPrologueWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPrologueWorklist.back().first->setPrologueData(C); else return error("Expected a constant"); } FunctionPrologueWorklist.pop_back(); } while (!FunctionPersonalityFnWorklist.empty()) { unsigned ValID = FunctionPersonalityFnWorklist.back().second; if (ValID >= ValueList.size()) { FunctionPersonalityFns.push_back(FunctionPersonalityFnWorklist.back()); } else { if (Constant *C = dyn_cast_or_null(ValueList[ValID])) FunctionPersonalityFnWorklist.back().first->setPersonalityFn(C); else return error("Expected a constant"); } FunctionPersonalityFnWorklist.pop_back(); } return Error::success(); } static APInt readWideAPInt(ArrayRef Vals, unsigned TypeBits) { SmallVector Words(Vals.size()); transform(Vals, Words.begin(), BitcodeReader::decodeSignRotatedValue); return APInt(TypeBits, Words); } Error BitcodeReader::parseConstants() { if (Error Err = Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID)) return Err; SmallVector Record; // Read all the records for this value table. Type *CurTy = Type::getInt32Ty(Context); Type *CurFullTy = Type::getInt32Ty(Context); unsigned NextCstNo = ValueList.size(); while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: if (NextCstNo != ValueList.size()) return error("Invalid constant reference"); // Once all the constants have been read, go through and resolve forward // references. ValueList.resolveConstantForwardRefs(); return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Type *VoidType = Type::getVoidTy(Context); Value *V = nullptr; Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (unsigned BitCode = MaybeBitCode.get()) { default: // Default behavior: unknown constant case bitc::CST_CODE_UNDEF: // UNDEF V = UndefValue::get(CurTy); break; case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid] if (Record.empty()) return error("Invalid record"); if (Record[0] >= TypeList.size() || !TypeList[Record[0]]) return error("Invalid record"); if (TypeList[Record[0]] == VoidType) return error("Invalid constant type"); CurFullTy = TypeList[Record[0]]; CurTy = flattenPointerTypes(CurFullTy); continue; // Skip the ValueList manipulation. case bitc::CST_CODE_NULL: // NULL V = Constant::getNullValue(CurTy); break; case bitc::CST_CODE_INTEGER: // INTEGER: [intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0])); break; case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); APInt VInt = readWideAPInt(Record, cast(CurTy)->getBitWidth()); V = ConstantInt::get(Context, VInt); break; } case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval] if (Record.empty()) return error("Invalid record"); if (CurTy->isHalfTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf(), APInt(16, (uint16_t)Record[0]))); else if (CurTy->isFloatTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle(), APInt(32, (uint32_t)Record[0]))); else if (CurTy->isDoubleTy()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble(), APInt(64, Record[0]))); else if (CurTy->isX86_FP80Ty()) { // Bits are not stored the same way as a normal i80 APInt, compensate. uint64_t Rearrange[2]; Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16); Rearrange[1] = Record[0] >> 48; V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended(), APInt(80, Rearrange))); } else if (CurTy->isFP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad(), APInt(128, Record))); else if (CurTy->isPPC_FP128Ty()) V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble(), APInt(128, Record))); else V = UndefValue::get(CurTy); break; } case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number] if (Record.empty()) return error("Invalid record"); unsigned Size = Record.size(); SmallVector Elts; if (StructType *STy = dyn_cast(CurTy)) { for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); } else if (ArrayType *ATy = dyn_cast(CurTy)) { Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantArray::get(ATy, Elts); } else if (VectorType *VTy = dyn_cast(CurTy)) { Type *EltTy = VTy->getElementType(); for (unsigned i = 0; i != Size; ++i) Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); V = ConstantVector::get(Elts); } else { V = UndefValue::get(CurTy); } break; } case bitc::CST_CODE_STRING: // STRING: [values] case bitc::CST_CODE_CSTRING: { // CSTRING: [values] if (Record.empty()) return error("Invalid record"); SmallString<16> Elts(Record.begin(), Record.end()); V = ConstantDataArray::getString(Context, Elts, BitCode == bitc::CST_CODE_CSTRING); break; } case bitc::CST_CODE_DATA: {// DATA: [n x value] if (Record.empty()) return error("Invalid record"); Type *EltTy = cast(CurTy)->getElementType(); if (EltTy->isIntegerTy(8)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(16)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(32)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isIntegerTy(64)) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::get(Context, Elts); else V = ConstantDataArray::get(Context, Elts); } else if (EltTy->isHalfTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isFloatTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else if (EltTy->isDoubleTy()) { SmallVector Elts(Record.begin(), Record.end()); if (isa(CurTy)) V = ConstantDataVector::getFP(Context, Elts); else V = ConstantDataArray::getFP(Context, Elts); } else { return error("Invalid type for value"); } break; } case bitc::CST_CODE_CE_UNOP: { // CE_UNOP: [opcode, opval] if (Record.size() < 2) return error("Invalid record"); int Opc = getDecodedUnaryOpcode(Record[0], CurTy); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown unop. } else { Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); unsigned Flags = 0; V = ConstantExpr::get(Opc, LHS, Flags); } break; } case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[0], CurTy); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown binop. } else { Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy); unsigned Flags = 0; if (Record.size() >= 4) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoSignedWrap; if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoUnsignedWrap; } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[3] & (1 << bitc::PEO_EXACT)) Flags |= SDivOperator::IsExact; } } V = ConstantExpr::get(Opc, LHS, RHS, Flags); } break; } case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] if (Record.size() < 3) return error("Invalid record"); int Opc = getDecodedCastOpcode(Record[0]); if (Opc < 0) { V = UndefValue::get(CurTy); // Unknown cast. } else { Type *OpTy = getTypeByID(Record[1]); if (!OpTy) return error("Invalid record"); Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy); V = upgradeBitCastExpr(Opc, Op, CurTy); if (!V) V = ConstantExpr::getCast(Opc, Op, CurTy); } break; } case bitc::CST_CODE_CE_INBOUNDS_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP: // [ty, n x operands] case bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX: { // [ty, flags, n x // operands] unsigned OpNum = 0; Type *PointeeType = nullptr; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX || Record.size() % 2) PointeeType = getTypeByID(Record[OpNum++]); bool InBounds = false; Optional InRangeIndex; if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX) { uint64_t Op = Record[OpNum++]; InBounds = Op & 1; InRangeIndex = Op >> 1; } else if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP) InBounds = true; SmallVector Elts; Type *Elt0FullTy = nullptr; while (OpNum != Record.size()) { if (!Elt0FullTy) Elt0FullTy = getFullyStructuredTypeByID(Record[OpNum]); Type *ElTy = getTypeByID(Record[OpNum++]); if (!ElTy) return error("Invalid record"); Elts.push_back(ValueList.getConstantFwdRef(Record[OpNum++], ElTy)); } if (Elts.size() < 1) return error("Invalid gep with no operands"); Type *ImplicitPointeeType = getPointerElementFlatType(Elt0FullTy->getScalarType()); if (!PointeeType) PointeeType = ImplicitPointeeType; else if (PointeeType != ImplicitPointeeType) return error("Explicit gep operator type does not match pointee type " "of pointer operand"); ArrayRef Indices(Elts.begin() + 1, Elts.end()); V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices, InBounds, InRangeIndex); break; } case bitc::CST_CODE_CE_SELECT: { // CE_SELECT: [opval#, opval#, opval#] if (Record.size() < 3) return error("Invalid record"); Type *SelectorTy = Type::getInt1Ty(Context); // The selector might be an i1 or an // Get the type from the ValueList before getting a forward ref. if (VectorType *VTy = dyn_cast(CurTy)) if (Value *V = ValueList[Record[0]]) if (SelectorTy != V->getType()) SelectorTy = VectorType::get(SelectorTy, VTy->getNumElements()); V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0], SelectorTy), ValueList.getConstantFwdRef(Record[1],CurTy), ValueList.getConstantFwdRef(Record[2],CurTy)); break; } case bitc::CST_CODE_CE_EXTRACTELT : { // CE_EXTRACTELT: [opty, opval, opty, opval] if (Record.size() < 3) return error("Invalid record"); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op1 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op1) return error("Invalid record"); V = ConstantExpr::getExtractElement(Op0, Op1); break; } case bitc::CST_CODE_CE_INSERTELT : { // CE_INSERTELT: [opval, opval, opty, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy->getElementType()); Constant *Op2 = nullptr; if (Record.size() == 4) { Type *IdxTy = getTypeByID(Record[2]); if (!IdxTy) return error("Invalid record"); Op2 = ValueList.getConstantFwdRef(Record[3], IdxTy); } else // TODO: Remove with llvm 4.0 Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); if (!Op2) return error("Invalid record"); V = ConstantExpr::getInsertElement(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval] VectorType *OpTy = dyn_cast(CurTy); if (Record.size() < 3 || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), OpTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval] VectorType *RTy = dyn_cast(CurTy); VectorType *OpTy = dyn_cast_or_null(getTypeByID(Record[0])); if (Record.size() < 4 || !RTy || !OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), RTy->getNumElements()); Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy); V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); break; } case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred] if (Record.size() < 4) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); if (!OpTy) return error("Invalid record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); if (OpTy->isFPOrFPVectorTy()) V = ConstantExpr::getFCmp(Record[3], Op0, Op1); else V = ConstantExpr::getICmp(Record[3], Op0, Op1); break; } // This maintains backward compatibility, pre-asm dialect keywords. // FIXME: Remove with the 4.0 release. case bitc::CST_CODE_INLINEASM_OLD: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = Record[0] >> 1; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; UpgradeInlineAsmString(&AsmStr); V = InlineAsm::get( cast(getPointerElementFlatType(CurFullTy)), AsmStr, ConstrStr, HasSideEffects, IsAlignStack); break; } // This version adds support for the asm dialect keywords (e.g., // inteldialect). case bitc::CST_CODE_INLINEASM: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; bool HasSideEffects = Record[0] & 1; bool IsAlignStack = (Record[0] >> 1) & 1; unsigned AsmDialect = Record[0] >> 2; unsigned AsmStrSize = Record[1]; if (2+AsmStrSize >= Record.size()) return error("Invalid record"); unsigned ConstStrSize = Record[2+AsmStrSize]; if (3+AsmStrSize+ConstStrSize > Record.size()) return error("Invalid record"); for (unsigned i = 0; i != AsmStrSize; ++i) AsmStr += (char)Record[2+i]; for (unsigned i = 0; i != ConstStrSize; ++i) ConstrStr += (char)Record[3+AsmStrSize+i]; UpgradeInlineAsmString(&AsmStr); V = InlineAsm::get( cast(getPointerElementFlatType(CurFullTy)), AsmStr, ConstrStr, HasSideEffects, IsAlignStack, InlineAsm::AsmDialect(AsmDialect)); break; } case bitc::CST_CODE_BLOCKADDRESS:{ if (Record.size() < 3) return error("Invalid record"); Type *FnTy = getTypeByID(Record[0]); if (!FnTy) return error("Invalid record"); Function *Fn = dyn_cast_or_null(ValueList.getConstantFwdRef(Record[1],FnTy)); if (!Fn) return error("Invalid record"); // If the function is already parsed we can insert the block address right // away. BasicBlock *BB; unsigned BBID = Record[2]; if (!BBID) // Invalid reference to entry block. return error("Invalid ID"); if (!Fn->empty()) { Function::iterator BBI = Fn->begin(), BBE = Fn->end(); for (size_t I = 0, E = BBID; I != E; ++I) { if (BBI == BBE) return error("Invalid ID"); ++BBI; } BB = &*BBI; } else { // Otherwise insert a placeholder and remember it so it can be inserted // when the function is parsed. auto &FwdBBs = BasicBlockFwdRefs[Fn]; if (FwdBBs.empty()) BasicBlockFwdRefQueue.push_back(Fn); if (FwdBBs.size() < BBID + 1) FwdBBs.resize(BBID + 1); if (!FwdBBs[BBID]) FwdBBs[BBID] = BasicBlock::Create(Context); BB = FwdBBs[BBID]; } V = BlockAddress::get(Fn, BB); break; } } IGC_ASSERT(V->getType() == flattenPointerTypes(CurFullTy) && "Incorrect fully structured type provided for Constant"); ValueList.assignValue(V, NextCstNo, CurFullTy); ++NextCstNo; } } Error BitcodeReader::parseUseLists() { if (Error Err = Stream.EnterSubBlock(bitc::USELIST_BLOCK_ID)) return Err; // Read all the records. SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a use list record. Record.clear(); bool IsBB = false; Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: unknown type. break; case bitc::USELIST_CODE_BB: IsBB = true; LLVM_FALLTHROUGH; case bitc::USELIST_CODE_DEFAULT: { unsigned RecordLength = Record.size(); if (RecordLength < 3) // Records should have at least an ID and two indexes. return error("Invalid record"); unsigned ID = Record.back(); Record.pop_back(); Value *V; if (IsBB) { IGC_ASSERT(ID < FunctionBBs.size() && "Basic block not found"); V = FunctionBBs[ID]; } else V = ValueList[ID]; unsigned NumUses = 0; SmallDenseMap Order; for (const Use &U : V->materialized_uses()) { if (++NumUses > Record.size()) break; Order[&U] = Record[NumUses - 1]; } if (Order.size() != Record.size() || NumUses > Record.size()) // Mismatches can happen if the functions are being materialized lazily // (out-of-order), or a value has been upgraded. break; V->sortUseList([&](const Use &L, const Use &R) { return Order.lookup(&L) < Order.lookup(&R); }); break; } } } } /// When we see the block for metadata, remember where it is and then skip it. /// This lets us lazily deserialize the metadata. Error BitcodeReader::rememberAndSkipMetadata() { // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); DeferredMetadataInfo.push_back(CurBit); // Skip over the block for now. if (Error Err = Stream.SkipBlock()) return Err; return Error::success(); } Error BitcodeReader::materializeMetadata() { for (uint64_t BitPos : DeferredMetadataInfo) { // Move the bit stream to the saved position. if (Error JumpFailed = Stream.JumpToBit(BitPos)) return JumpFailed; if (Error Err = MDLoader->parseModuleMetadata()) return Err; } // Upgrade "Linker Options" module flag to "llvm.linker.options" module-level // metadata. if (Metadata *Val = TheModule->getModuleFlag("Linker Options")) { NamedMDNode *LinkerOpts = TheModule->getOrInsertNamedMetadata("llvm.linker.options"); for (const MDOperand &MDOptions : cast(Val)->operands()) LinkerOpts->addOperand(cast(MDOptions)); } DeferredMetadataInfo.clear(); return Error::success(); } void BitcodeReader::setStripDebugInfo() { StripDebugInfo = true; } /// When we see the block for a function body, remember where it is and then /// skip it. This lets us lazily deserialize the functions. Error BitcodeReader::rememberAndSkipFunctionBody() { // Get the function we are talking about. if (FunctionsWithBodies.empty()) return error("Insufficient function protos"); Function *Fn = FunctionsWithBodies.back(); FunctionsWithBodies.pop_back(); // Save the current stream state. uint64_t CurBit = Stream.GetCurrentBitNo(); IGC_ASSERT( (DeferredFunctionInfo[Fn] == 0 || DeferredFunctionInfo[Fn] == CurBit) && "Mismatch between VST and scanned function offsets"); DeferredFunctionInfo[Fn] = CurBit; // Skip over the function block for now. if (Error Err = Stream.SkipBlock()) return Err; return Error::success(); } Error BitcodeReader::globalCleanup() { // Patch the initializers for globals and aliases up. if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; if (!GlobalInits.empty() || !IndirectSymbolInits.empty()) return error("Malformed global initializer set"); // Look for intrinsic functions which need to be upgraded at some point for (Function &F : *TheModule) { MDLoader->upgradeDebugIntrinsics(F); Function *NewFn; if (UpgradeIntrinsicFunction(&F, NewFn)) UpgradedIntrinsics[&F] = NewFn; else if (auto Remangled = Intrinsic::remangleIntrinsicFunction(&F)) // Some types could be renamed during loading if several modules are // loaded in the same LLVMContext (LTO scenario). In this case we should // remangle intrinsics names as well. RemangledIntrinsics[&F] = Remangled.getValue(); } // Look for global variables which need to be renamed. std::vector> UpgradedVariables; for (GlobalVariable &GV : TheModule->globals()) if (GlobalVariable *Upgraded = UpgradeGlobalVariable(&GV)) UpgradedVariables.emplace_back(&GV, Upgraded); for (auto &Pair : UpgradedVariables) { Pair.first->eraseFromParent(); TheModule->getGlobalList().push_back(Pair.second); } // Force deallocation of memory for these vectors to favor the client that // want lazy deserialization. std::vector>().swap(GlobalInits); std::vector>().swap( IndirectSymbolInits); return Error::success(); } /// Support for lazy parsing of function bodies. This is required if we /// either have an old bitcode file without a VST forward declaration record, /// or if we have an anonymous function being materialized, since anonymous /// functions do not have a name and are therefore not in the VST. Error BitcodeReader::rememberAndSkipFunctionBodies() { if (Error JumpFailed = Stream.JumpToBit(NextUnreadBit)) return JumpFailed; if (Stream.AtEndOfStream()) return error("Could not find function in stream"); if (!SeenFirstFunctionBody) return error("Trying to materialize functions before seeing function blocks"); // An old bitcode file with the symbol table at the end would have // finished the parse greedily. IGC_ASSERT(SeenValueSymbolTable); SmallVector Record; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { default: return error("Expect SubBlock"); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: return error("Expect function block"); case bitc::FUNCTION_BLOCK_ID: if (Error Err = rememberAndSkipFunctionBody()) return Err; NextUnreadBit = Stream.GetCurrentBitNo(); return Error::success(); } } } } bool BitcodeReaderBase::readBlockInfo() { Expected> MaybeNewBlockInfo = Stream.ReadBlockInfoBlock(); if (!MaybeNewBlockInfo) return true; // FIXME Handle the error. Optional NewBlockInfo = std::move(MaybeNewBlockInfo.get()); if (!NewBlockInfo) return true; BlockInfo = std::move(*NewBlockInfo); return false; } Error BitcodeReader::parseComdatRecord(ArrayRef Record) { // v1: [selection_kind, name] // v2: [strtab_offset, strtab_size, selection_kind] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.empty()) return error("Invalid record"); Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]); std::string OldFormatName; if (!UseStrtab) { if (Record.size() < 2) return error("Invalid record"); unsigned ComdatNameSize = Record[1]; OldFormatName.reserve(ComdatNameSize); for (unsigned i = 0; i != ComdatNameSize; ++i) OldFormatName += (char)Record[2 + i]; Name = OldFormatName; } Comdat *C = TheModule->getOrInsertComdat(Name); C->setSelectionKind(SK); ComdatList.push_back(C); return Error::success(); } static void inferDSOLocal(GlobalValue *GV) { // infer dso_local from linkage and visibility if it is not encoded. if (GV->hasLocalLinkage() || (!GV->hasDefaultVisibility() && !GV->hasExternalWeakLinkage())) GV->setDSOLocal(true); } Error BitcodeReader::parseGlobalVarRecord(ArrayRef Record) { // v1: [pointer type, isconst, initid, linkage, alignment, section, // visibility, threadlocal, unnamed_addr, externally_initialized, // dllstorageclass, comdat, attributes, preemption specifier, // partition strtab offset, partition strtab size] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.size() < 6) return error("Invalid record"); Type *FullTy = getFullyStructuredTypeByID(Record[0]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); bool isConstant = Record[1] & 1; bool explicitType = Record[1] & 2; unsigned AddressSpace; if (explicitType) { AddressSpace = Record[1] >> 2; } else { if (!Ty->isPointerTy()) return error("Invalid type for value"); AddressSpace = cast(Ty)->getAddressSpace(); std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); } uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); unsigned Alignment; if (Error Err = parseAlignmentValue(Record[4], Alignment)) return Err; std::string Section; if (Record[5]) { if (Record[5] - 1 >= SectionTable.size()) return error("Invalid ID"); Section = SectionTable[Record[5] - 1]; } GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; // Local linkage must have default visibility. if (Record.size() > 6 && !GlobalValue::isLocalLinkage(Linkage)) // FIXME: Change to an error if non-default in 4.0. Visibility = getDecodedVisibility(Record[6]); GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; if (Record.size() > 7) TLM = getDecodedThreadLocalMode(Record[7]); GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 8) UnnamedAddr = getDecodedUnnamedAddrType(Record[8]); bool ExternallyInitialized = false; if (Record.size() > 9) ExternallyInitialized = Record[9]; GlobalVariable *NewGV = new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, Name, nullptr, TLM, AddressSpace, ExternallyInitialized); NewGV->setAlignment(Alignment); if (!Section.empty()) NewGV->setSection(Section); NewGV->setVisibility(Visibility); NewGV->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10) NewGV->setDLLStorageClass(getDecodedDLLStorageClass(Record[10])); else upgradeDLLImportExportLinkage(NewGV, RawLinkage); FullTy = PointerType::get(FullTy, AddressSpace); IGC_ASSERT(NewGV->getType() == flattenPointerTypes(FullTy) && "Incorrect fully specified type for GlobalVariable"); ValueList.push_back(NewGV, FullTy); // Remember which value to use for the global initializer. if (unsigned InitID = Record[2]) GlobalInits.push_back(std::make_pair(NewGV, InitID - 1)); if (Record.size() > 11) { if (unsigned ComdatID = Record[11]) { if (ComdatID > ComdatList.size()) return error("Invalid global variable comdat ID"); NewGV->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { NewGV->setComdat(reinterpret_cast(1)); } if (Record.size() > 12) { auto AS = getAttributes(Record[12]).getFnAttributes(); NewGV->setAttributes(AS); } if (Record.size() > 13) { NewGV->setDSOLocal(getDecodedDSOLocal(Record[13])); } inferDSOLocal(NewGV); // Check whether we have enough values to read a partition name. if (Record.size() > 15) NewGV->setPartition(StringRef(Strtab.data() + Record[14], Record[15])); return Error::success(); } Error BitcodeReader::parseFunctionRecord(ArrayRef Record) { // v1: [type, callingconv, isproto, linkage, paramattr, alignment, section, // visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat, // prefixdata, personalityfn, preemption specifier, addrspace] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); if (Record.size() < 8) return error("Invalid record"); Type *FullFTy = getFullyStructuredTypeByID(Record[0]); Type *FTy = flattenPointerTypes(FullFTy); if (!FTy) return error("Invalid record"); if (isa(FTy)) std::tie(FullFTy, FTy) = getPointerElementTypes(FullFTy); if (!isa(FTy)) return error("Invalid type for value"); auto CC = static_cast(Record[1]); if (CC & ~CallingConv::MaxID) return error("Invalid calling convention ID"); unsigned AddrSpace = TheModule->getDataLayout().getProgramAddressSpace(); if (Record.size() > 16) AddrSpace = Record[16]; Function *Func = Function::Create(cast(FTy), GlobalValue::ExternalLinkage, AddrSpace, Name, TheModule); IGC_ASSERT(Func->getFunctionType() == flattenPointerTypes(FullFTy) && "Incorrect fully specified type provided for function"); FunctionTypes[Func] = cast(FullFTy); Func->setCallingConv(CC); bool isProto = Record[2]; uint64_t RawLinkage = Record[3]; Func->setLinkage(getDecodedLinkage(RawLinkage)); Func->setAttributes(getAttributes(Record[4])); // Upgrade any old-style byval without a type by propagating the argument's // pointee type. There should be no opaque pointers where the byval type is // implicit. for (unsigned i = 0; i != Func->arg_size(); ++i) { if (!Func->hasParamAttribute(i, Attribute::ByVal)) continue; Type *PTy = cast(FullFTy)->getParamType(i); Func->removeParamAttr(i, Attribute::ByVal); Func->addParamAttr(i, Attribute::getWithByValType( Context, getPointerElementFlatType(PTy))); } unsigned Alignment; if (Error Err = parseAlignmentValue(Record[5], Alignment)) return Err; Func->setAlignment(Alignment); if (Record[6]) { if (Record[6] - 1 >= SectionTable.size()) return error("Invalid ID"); Func->setSection(SectionTable[Record[6] - 1]); } // Local linkage must have default visibility. if (!Func->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. Func->setVisibility(getDecodedVisibility(Record[7])); if (Record.size() > 8 && Record[8]) { if (Record[8] - 1 >= GCTable.size()) return error("Invalid ID"); Func->setGC(GCTable[Record[8] - 1]); } GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; if (Record.size() > 9) UnnamedAddr = getDecodedUnnamedAddrType(Record[9]); Func->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10 && Record[10] != 0) FunctionPrologues.push_back(std::make_pair(Func, Record[10] - 1)); if (Record.size() > 11) Func->setDLLStorageClass(getDecodedDLLStorageClass(Record[11])); else upgradeDLLImportExportLinkage(Func, RawLinkage); if (Record.size() > 12) { if (unsigned ComdatID = Record[12]) { if (ComdatID > ComdatList.size()) return error("Invalid function comdat ID"); Func->setComdat(ComdatList[ComdatID - 1]); } } else if (hasImplicitComdat(RawLinkage)) { Func->setComdat(reinterpret_cast(1)); } if (Record.size() > 13 && Record[13] != 0) FunctionPrefixes.push_back(std::make_pair(Func, Record[13] - 1)); if (Record.size() > 14 && Record[14] != 0) FunctionPersonalityFns.push_back(std::make_pair(Func, Record[14] - 1)); if (Record.size() > 15) { Func->setDSOLocal(getDecodedDSOLocal(Record[15])); } inferDSOLocal(Func); // Record[16] is the address space number. // Check whether we have enough values to read a partition name. if (Record.size() > 18) Func->setPartition(StringRef(Strtab.data() + Record[17], Record[18])); Type *FullTy = PointerType::get(FullFTy, AddrSpace); IGC_ASSERT(Func->getType() == flattenPointerTypes(FullTy) && "Incorrect fully specified type provided for Function"); ValueList.push_back(Func, FullTy); // If this is a function with a body, remember the prototype we are // creating now, so that we can match up the body with them later. if (!isProto) { Func->setIsMaterializable(true); FunctionsWithBodies.push_back(Func); DeferredFunctionInfo[Func] = 0; } return Error::success(); } Error BitcodeReader::parseGlobalIndirectSymbolRecord( unsigned BitCode, ArrayRef Record) { // v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST) // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, // dllstorageclass, threadlocal, unnamed_addr, // preemption specifier] (name in VST) // v1 IFUNC: [alias type, addrspace, aliasee val#, linkage, // visibility, dllstorageclass, threadlocal, unnamed_addr, // preemption specifier] (name in VST) // v2: [strtab_offset, strtab_size, v1] StringRef Name; std::tie(Name, Record) = readNameFromStrtab(Record); bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD; if (Record.size() < (3 + (unsigned)NewRecord)) return error("Invalid record"); unsigned OpNum = 0; Type *FullTy = getFullyStructuredTypeByID(Record[OpNum++]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); unsigned AddrSpace; if (!NewRecord) { auto *PTy = dyn_cast(Ty); if (!PTy) return error("Invalid type for value"); std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); AddrSpace = PTy->getAddressSpace(); } else { AddrSpace = Record[OpNum++]; } auto Val = Record[OpNum++]; auto Linkage = Record[OpNum++]; GlobalIndirectSymbol *NewGA; if (BitCode == bitc::MODULE_CODE_ALIAS || BitCode == bitc::MODULE_CODE_ALIAS_OLD) NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name, TheModule); else NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name, nullptr, TheModule); IGC_ASSERT(NewGA->getValueType() == flattenPointerTypes(FullTy) && "Incorrect fully structured type provided for GlobalIndirectSymbol"); // Old bitcode files didn't have visibility field. // Local linkage must have default visibility. if (OpNum != Record.size()) { auto VisInd = OpNum++; if (!NewGA->hasLocalLinkage()) // FIXME: Change to an error if non-default in 4.0. NewGA->setVisibility(getDecodedVisibility(Record[VisInd])); } if (BitCode == bitc::MODULE_CODE_ALIAS || BitCode == bitc::MODULE_CODE_ALIAS_OLD) { if (OpNum != Record.size()) NewGA->setDLLStorageClass(getDecodedDLLStorageClass(Record[OpNum++])); else upgradeDLLImportExportLinkage(NewGA, Linkage); if (OpNum != Record.size()) NewGA->setThreadLocalMode(getDecodedThreadLocalMode(Record[OpNum++])); if (OpNum != Record.size()) NewGA->setUnnamedAddr(getDecodedUnnamedAddrType(Record[OpNum++])); } if (OpNum != Record.size()) NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++])); inferDSOLocal(NewGA); // Check whether we have enough values to read a partition name. if (OpNum + 1 < Record.size()) { NewGA->setPartition( StringRef(Strtab.data() + Record[OpNum], Record[OpNum + 1])); OpNum += 2; } FullTy = PointerType::get(FullTy, AddrSpace); IGC_ASSERT(NewGA->getType() == flattenPointerTypes(FullTy) && "Incorrect fully structured type provided for GlobalIndirectSymbol"); ValueList.push_back(NewGA, FullTy); IndirectSymbolInits.push_back(std::make_pair(NewGA, Val)); return Error::success(); } Error BitcodeReader::parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata) { if (ResumeBit) { if (Error JumpFailed = Stream.JumpToBit(ResumeBit)) return JumpFailed; } else if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return Err; SmallVector Record; // Read all the records for this module. while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return globalCleanup(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Error Err = Stream.SkipBlock()) return Err; break; case bitc::BLOCKINFO_BLOCK_ID: if (readBlockInfo()) return error("Malformed block"); break; case bitc::PARAMATTR_BLOCK_ID: if (Error Err = parseAttributeBlock()) return Err; break; case bitc::PARAMATTR_GROUP_BLOCK_ID: if (Error Err = parseAttributeGroupBlock()) return Err; break; case bitc::TYPE_BLOCK_ID_NEW: if (Error Err = parseTypeTable()) return Err; break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (!SeenValueSymbolTable) { // Either this is an old form VST without function index and an // associated VST forward declaration record (which would have caused // the VST to be jumped to and parsed before it was encountered // normally in the stream), or there were no function blocks to // trigger an earlier parsing of the VST. IGC_ASSERT(VSTOffset == 0 || FunctionsWithBodies.empty()); if (Error Err = parseValueSymbolTable()) return Err; SeenValueSymbolTable = true; } else { // We must have had a VST forward declaration record, which caused // the parser to jump to and parse the VST earlier. IGC_ASSERT(VSTOffset > 0); if (Error Err = Stream.SkipBlock()) return Err; } break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; if (Error Err = resolveGlobalAndIndirectSymbolInits()) return Err; break; case bitc::METADATA_BLOCK_ID: if (ShouldLazyLoadMetadata) { if (Error Err = rememberAndSkipMetadata()) return Err; break; } IGC_ASSERT(DeferredMetadataInfo.empty() && "Unexpected deferred metadata"); if (Error Err = MDLoader->parseModuleMetadata()) return Err; break; case bitc::METADATA_KIND_BLOCK_ID: if (Error Err = MDLoader->parseMetadataKinds()) return Err; break; case bitc::FUNCTION_BLOCK_ID: // If this is the first function body we've seen, reverse the // FunctionsWithBodies list. if (!SeenFirstFunctionBody) { std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end()); if (Error Err = globalCleanup()) return Err; SeenFirstFunctionBody = true; } if (VSTOffset > 0) { // If we have a VST forward declaration record, make sure we // parse the VST now if we haven't already. It is needed to // set up the DeferredFunctionInfo vector for lazy reading. if (!SeenValueSymbolTable) { if (Error Err = BitcodeReader::parseValueSymbolTable(VSTOffset)) return Err; SeenValueSymbolTable = true; // Fall through so that we record the NextUnreadBit below. // This is necessary in case we have an anonymous function that // is later materialized. Since it will not have a VST entry we // need to fall back to the lazy parse to find its offset. } else { // If we have a VST forward declaration record, but have already // parsed the VST (just above, when the first function body was // encountered here), then we are resuming the parse after // materializing functions. The ResumeBit points to the // start of the last function block recorded in the // DeferredFunctionInfo map. Skip it. if (Error Err = Stream.SkipBlock()) return Err; continue; } } // Support older bitcode files that did not have the function // index in the VST, nor a VST forward declaration record, as // well as anonymous functions that do not have VST entries. // Build the DeferredFunctionInfo vector on the fly. if (Error Err = rememberAndSkipFunctionBody()) return Err; // Suspend parsing when we reach the function bodies. Subsequent // materialization calls will resume it when necessary. If the bitcode // file is old, the symbol table will be at the end instead and will not // have been seen yet. In this case, just finish the parse now. if (SeenValueSymbolTable) { NextUnreadBit = Stream.GetCurrentBitNo(); // After the VST has been parsed, we need to make sure intrinsic name // are auto-upgraded. return globalCleanup(); } break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: if (Error Err = parseOperandBundleTags()) return Err; break; case bitc::SYNC_SCOPE_NAMES_BLOCK_ID: if (Error Err = parseSyncScopeNames()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (unsigned BitCode = MaybeBitCode.get()) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { Expected VersionOrErr = parseVersionRecord(Record); if (!VersionOrErr) return VersionOrErr.takeError(); UseRelativeIDs = *VersionOrErr >= 1; break; } case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setTargetTriple(S); break; } case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); size_t index = S.find("-a64:64:64"); if (index != std::string::npos) S.replace(index, 10, ""); TheModule->setDataLayout(S); break; } case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); TheModule->setModuleInlineAsm(S); break; } case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N] // FIXME: Remove in 4.0. std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); // Ignore value. break; } case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); SectionTable.push_back(S); break; } case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N] std::string S; if (convertToString(Record, 0, S)) return error("Invalid record"); GCTable.push_back(S); break; } case bitc::MODULE_CODE_COMDAT: if (Error Err = parseComdatRecord(Record)) return Err; break; case bitc::MODULE_CODE_GLOBALVAR: if (Error Err = parseGlobalVarRecord(Record)) return Err; break; case bitc::MODULE_CODE_FUNCTION: if (Error Err = parseFunctionRecord(Record)) return Err; break; case bitc::MODULE_CODE_IFUNC: case bitc::MODULE_CODE_ALIAS: case bitc::MODULE_CODE_ALIAS_OLD: if (Error Err = parseGlobalIndirectSymbolRecord(BitCode, Record)) return Err; break; /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one word // before the start of the identification or module block, which was // historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); TheModule->setSourceFileName(ValueName); break; } Record.clear(); } } Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata, bool IsImporting) { TheModule = M; MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting, [&](unsigned ID) { return getTypeByID(ID); }); return parseModule(0, ShouldLazyLoadMetadata); } Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) { if (!isa(PtrType)) return error("Load/Store operand is not a pointer type"); Type *ElemType = cast(PtrType)->getElementType(); if (ValType && ValType != ElemType) return error("Explicit load/store type does not match pointee " "type of pointer operand"); if (!PointerType::isLoadableOrStorableType(ElemType)) return error("Cannot load/store from pointer"); return Error::success(); } void BitcodeReader::propagateByValTypes(CallBase *CB, ArrayRef ArgsFullTys) { for (unsigned i = 0; i != CB->arg_size(); ++i) { if (!CB->paramHasAttr(i, Attribute::ByVal)) continue; CB->removeParamAttr(i, Attribute::ByVal); CB->addParamAttr( i, Attribute::getWithByValType( Context, getPointerElementFlatType(ArgsFullTys[i]))); } } /// Lazily parse the specified function body block. Error BitcodeReader::parseFunctionBody(Function *F) { if (Error Err = Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID)) return Err; // Unexpected unresolved metadata when parsing function. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: incoming forward references"); InstructionList.clear(); unsigned ModuleValueListSize = ValueList.size(); unsigned ModuleMDLoaderSize = MDLoader->size(); // Add all the function arguments to the value table. unsigned ArgNo = 0; FunctionType *FullFTy = FunctionTypes[F]; for (Argument &I : F->args()) { IGC_ASSERT(I.getType() == flattenPointerTypes(FullFTy->getParamType(ArgNo)) && "Incorrect fully specified type for Function Argument"); ValueList.push_back(&I, FullFTy->getParamType(ArgNo++)); } unsigned NextValueNo = ValueList.size(); BasicBlock *CurBB = nullptr; unsigned CurBBNo = 0; DebugLoc LastLoc; auto getLastInstruction = [&]() -> Instruction * { if (CurBB && !CurBB->empty()) return &CurBB->back(); else if (CurBBNo && FunctionBBs[CurBBNo - 1] && !FunctionBBs[CurBBNo - 1]->empty()) return &FunctionBBs[CurBBNo - 1]->back(); return nullptr; }; std::vector OperandBundles; // Read all the records. SmallVector Record; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: goto OutOfRecordLoop; case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Error Err = Stream.SkipBlock()) return Err; break; case bitc::CONSTANTS_BLOCK_ID: if (Error Err = parseConstants()) return Err; NextValueNo = ValueList.size(); break; case bitc::VALUE_SYMTAB_BLOCK_ID: if (Error Err = parseValueSymbolTable()) return Err; break; case bitc::METADATA_ATTACHMENT_ID: if (Error Err = MDLoader->parseMetadataAttachment(*F, InstructionList)) return Err; break; case bitc::METADATA_BLOCK_ID: IGC_ASSERT(DeferredMetadataInfo.empty() && "Must read all module-level metadata before function-level"); if (Error Err = MDLoader->parseFunctionMetadata()) return Err; break; case bitc::USELIST_BLOCK_ID: if (Error Err = parseUseLists()) return Err; break; } continue; case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Instruction *I = nullptr; Type *FullTy = nullptr; Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (unsigned BitCode = MaybeBitCode.get()) { default: // Default behavior: reject return error("Invalid value"); case bitc::FUNC_CODE_DECLAREBLOCKS: { // DECLAREBLOCKS: [nblocks] if (Record.size() < 1 || Record[0] == 0) return error("Invalid record"); // Create all the basic blocks for the function. FunctionBBs.resize(Record[0]); // See if anything took the address of blocks in this function. auto BBFRI = BasicBlockFwdRefs.find(F); if (BBFRI == BasicBlockFwdRefs.end()) { for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i) FunctionBBs[i] = BasicBlock::Create(Context, "", F); } else { auto &BBRefs = BBFRI->second; // Check for invalid basic block references. if (BBRefs.size() > FunctionBBs.size()) return error("Invalid ID"); IGC_ASSERT(!BBRefs.empty() && "Unexpected empty array"); IGC_ASSERT(!BBRefs.front() && "Invalid reference to entry block"); for (unsigned I = 0, E = FunctionBBs.size(), RE = BBRefs.size(); I != E; ++I) if (I < RE && BBRefs[I]) { BBRefs[I]->insertInto(F); FunctionBBs[I] = BBRefs[I]; } else { FunctionBBs[I] = BasicBlock::Create(Context, "", F); } // Erase from the table. BasicBlockFwdRefs.erase(BBFRI); } CurBB = FunctionBBs[0]; continue; } case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN // This record indicates that the last instruction is at the same // location as the previous instruction with a location. I = getLastInstruction(); if (!I) return error("Invalid record"); I->setDebugLoc(LastLoc); I = nullptr; continue; case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia] I = getLastInstruction(); if (!I || Record.size() < 4) return error("Invalid record"); unsigned Line = Record[0], Col = Record[1]; unsigned ScopeID = Record[2], IAID = Record[3]; bool isImplicitCode = Record.size() == 5 && Record[4]; MDNode *Scope = nullptr, *IA = nullptr; if (ScopeID) { Scope = dyn_cast_or_null( MDLoader->getMetadataFwdRefOrLoad(ScopeID - 1)); if (!Scope) return error("Invalid record"); } if (IAID) { IA = dyn_cast_or_null( MDLoader->getMetadataFwdRefOrLoad(IAID - 1)); if (!IA) return error("Invalid record"); } LastLoc = DebugLoc::get(Line, Col, Scope, IA, isImplicitCode); I->setDebugLoc(LastLoc); I = nullptr; continue; } case bitc::FUNC_CODE_INST_UNOP: { // UNOP: [opval, ty, opcode] unsigned OpNum = 0; Value *LHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || OpNum+1 > Record.size()) return error("Invalid record"); int Opc = getDecodedUnaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return error("Invalid record"); I = UnaryOperator::Create((Instruction::UnaryOps)Opc, LHS); InstructionList.push_back(I); if (OpNum < Record.size()) { if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } } break; } case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode] unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS) || OpNum+1 > Record.size()) return error("Invalid record"); int Opc = getDecodedBinaryOpcode(Record[OpNum++], LHS->getType()); if (Opc == -1) return error("Invalid record"); I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); InstructionList.push_back(I); if (OpNum < Record.size()) { if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) cast(I)->setHasNoSignedWrap(true); if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) cast(I)->setHasNoUnsignedWrap(true); } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || Opc == Instruction::LShr || Opc == Instruction::AShr) { if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } else if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } } break; } case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op) || OpNum+2 != Record.size()) return error("Invalid record"); FullTy = getFullyStructuredTypeByID(Record[OpNum]); Type *ResTy = flattenPointerTypes(FullTy); int Opc = getDecodedCastOpcode(Record[OpNum + 1]); if (Opc == -1 || !ResTy) return error("Invalid record"); Instruction *Temp = nullptr; if ((I = UpgradeBitCastInst(Opc, Op, ResTy, Temp))) { if (Temp) { InstructionList.push_back(Temp); CurBB->getInstList().push_back(Temp); } } else { auto CastOp = (Instruction::CastOps)Opc; if (!CastInst::castIsValid(CastOp, Op, ResTy)) return error("Invalid cast"); I = CastInst::Create(CastOp, Op, ResTy); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD: case bitc::FUNC_CODE_INST_GEP_OLD: case bitc::FUNC_CODE_INST_GEP: { // GEP: type, [n x operands] unsigned OpNum = 0; Type *Ty; bool InBounds; if (BitCode == bitc::FUNC_CODE_INST_GEP) { InBounds = Record[OpNum++]; FullTy = getFullyStructuredTypeByID(Record[OpNum++]); Ty = flattenPointerTypes(FullTy); } else { InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD; Ty = nullptr; } Value *BasePtr; Type *FullBaseTy = nullptr; if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr, &FullBaseTy)) return error("Invalid record"); if (!Ty) { std::tie(FullTy, Ty) = getPointerElementTypes(FullBaseTy->getScalarType()); } else if (Ty != getPointerElementFlatType(FullBaseTy->getScalarType())) return error( "Explicit gep type does not match pointee type of pointer operand"); SmallVector GEPIdx; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); GEPIdx.push_back(Op); } I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx); FullTy = GetElementPtrInst::getGEPReturnType(FullTy, I, GEPIdx); InstructionList.push_back(I); if (InBounds) cast(I)->setIsInBounds(true); break; } case bitc::FUNC_CODE_INST_EXTRACTVAL: { // EXTRACTVAL: [opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg, &FullTy)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("EXTRACTVAL: Invalid instruction with 0 indices"); SmallVector EXTRACTVALIdx; for (; OpNum != RecSize; ++OpNum) { bool IsArray = FullTy->isArrayTy(); bool IsStruct = FullTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("EXTRACTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= FullTy->getStructNumElements()) return error("EXTRACTVAL: Invalid struct index"); if (IsArray && Index >= FullTy->getArrayNumElements()) return error("EXTRACTVAL: Invalid array index"); EXTRACTVALIdx.push_back((unsigned)Index); if (IsStruct) FullTy = FullTy->getStructElementType(Index); else FullTy = FullTy->getArrayElementType(); } I = ExtractValueInst::Create(Agg, EXTRACTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTVAL: { // INSERTVAL: [opty, opval, opty, opval, n x indices] unsigned OpNum = 0; Value *Agg; if (getValueTypePair(Record, OpNum, NextValueNo, Agg, &FullTy)) return error("Invalid record"); Value *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Val)) return error("Invalid record"); unsigned RecSize = Record.size(); if (OpNum == RecSize) return error("INSERTVAL: Invalid instruction with 0 indices"); SmallVector INSERTVALIdx; Type *CurTy = Agg->getType(); for (; OpNum != RecSize; ++OpNum) { bool IsArray = CurTy->isArrayTy(); bool IsStruct = CurTy->isStructTy(); uint64_t Index = Record[OpNum]; if (!IsStruct && !IsArray) return error("INSERTVAL: Invalid type"); if ((unsigned)Index != Index) return error("Invalid value"); if (IsStruct && Index >= CurTy->getStructNumElements()) return error("INSERTVAL: Invalid struct index"); if (IsArray && Index >= CurTy->getArrayNumElements()) return error("INSERTVAL: Invalid array index"); INSERTVALIdx.push_back((unsigned)Index); if (IsStruct) CurTy = CurTy->getStructElementType(Index); else CurTy = CurTy->getArrayElementType(); } if (CurTy != Val->getType()) return error("Inserted value type doesn't match aggregate type"); I = InsertValueInst::Create(Agg, Val, INSERTVALIdx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval] // obsolete form of select // handles select i1 ... in old bitcode unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal, &FullTy) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || popValue(Record, OpNum, NextValueNo, Type::getInt1Ty(Context), Cond)) return error("Invalid record"); I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred] // new form of select // handles select i1 or select [N x i1] unsigned OpNum = 0; Value *TrueVal, *FalseVal, *Cond; if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal, &FullTy) || popValue(Record, OpNum, NextValueNo, TrueVal->getType(), FalseVal) || getValueTypePair(Record, OpNum, NextValueNo, Cond)) return error("Invalid record"); // select condition can be either i1 or [N x i1] if (VectorType* vector_type = dyn_cast(Cond->getType())) { // expect if (vector_type->getElementType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } else { // expect i1 if (Cond->getType() != Type::getInt1Ty(Context)) return error("Invalid type for value"); } I = SelectInst::Create(Cond, TrueVal, FalseVal); InstructionList.push_back(I); if (OpNum < Record.size() && isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); if (FMF.any()) I->setFastMathFlags(FMF); } break; } case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval] unsigned OpNum = 0; Value *Vec, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec, &FullTy) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); I = ExtractElementInst::Create(Vec, Idx); FullTy = FullTy->getVectorElementType(); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval] unsigned OpNum = 0; Value *Vec, *Elt, *Idx; if (getValueTypePair(Record, OpNum, NextValueNo, Vec, &FullTy)) return error("Invalid record"); if (!Vec->getType()->isVectorTy()) return error("Invalid type for value"); if (popValue(Record, OpNum, NextValueNo, cast(Vec->getType())->getElementType(), Elt) || getValueTypePair(Record, OpNum, NextValueNo, Idx)) return error("Invalid record"); I = InsertElementInst::Create(Vec, Elt, Idx); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval] unsigned OpNum = 0; Value *Vec1, *Vec2, *Mask; if (getValueTypePair(Record, OpNum, NextValueNo, Vec1, &FullTy) || popValue(Record, OpNum, NextValueNo, Vec1->getType(), Vec2)) return error("Invalid record"); if (getValueTypePair(Record, OpNum, NextValueNo, Mask)) return error("Invalid record"); if (!Vec1->getType()->isVectorTy() || !Vec2->getType()->isVectorTy()) return error("Invalid type for value"); I = new ShuffleVectorInst(Vec1, Vec2, Mask); FullTy = VectorType::get(FullTy->getVectorElementType(), Mask->getType()->getVectorNumElements()); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred] // Old form of ICmp/FCmp returning bool // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were // both legal on vectors but had different behaviour. case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred] // FCmp/ICmp returning bool or vector of bool unsigned OpNum = 0; Value *LHS, *RHS; if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS)) return error("Invalid record"); if (OpNum >= Record.size()) return error( "Invalid record: operand number exceeded available operands"); unsigned PredVal = Record[OpNum]; bool IsFP = LHS->getType()->isFPOrFPVectorTy(); FastMathFlags FMF; if (IsFP && Record.size() > OpNum+1) FMF = getDecodedFastMathFlags(Record[++OpNum]); if (OpNum+1 != Record.size()) return error("Invalid record"); if (LHS->getType()->isFPOrFPVectorTy()) I = new FCmpInst((FCmpInst::Predicate)PredVal, LHS, RHS); else I = new ICmpInst((ICmpInst::Predicate)PredVal, LHS, RHS); if (FMF.any()) I->setFastMathFlags(FMF); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval] { unsigned Size = Record.size(); if (Size == 0) { I = ReturnInst::Create(Context); InstructionList.push_back(I); break; } unsigned OpNum = 0; Value *Op = nullptr; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); if (OpNum != Record.size()) return error("Invalid record"); I = ReturnInst::Create(Context, Op); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#] if (Record.size() != 1 && Record.size() != 3) return error("Invalid record"); BasicBlock *TrueDest = getBasicBlock(Record[0]); if (!TrueDest) return error("Invalid record"); if (Record.size() == 1) { I = BranchInst::Create(TrueDest); InstructionList.push_back(I); } else { BasicBlock *FalseDest = getBasicBlock(Record[1]); Value *Cond = getValue(Record, 2, NextValueNo, Type::getInt1Ty(Context)); if (!FalseDest || !Cond) return error("Invalid record"); I = BranchInst::Create(TrueDest, FalseDest, Cond); InstructionList.push_back(I); } break; } case bitc::FUNC_CODE_INST_CLEANUPRET: { // CLEANUPRET: [val] or [val,bb#] if (Record.size() != 1 && Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CleanupPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CleanupPad) return error("Invalid record"); BasicBlock *UnwindDest = nullptr; if (Record.size() == 2) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } I = CleanupReturnInst::Create(CleanupPad, UnwindDest); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHRET: { // CATCHRET: [val,bb#] if (Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; Value *CatchPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CatchPad) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); I = CatchReturnInst::Create(CatchPad, BB); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHSWITCH: { // CATCHSWITCH: [tok,num,(bb)*,bb?] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumHandlers = Record[Idx++]; SmallVector Handlers; for (unsigned Op = 0; Op != NumHandlers; ++Op) { BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); Handlers.push_back(BB); } BasicBlock *UnwindDest = nullptr; if (Idx + 1 == Record.size()) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } if (Record.size() != Idx) return error("Invalid record"); auto *CatchSwitch = CatchSwitchInst::Create(ParentPad, UnwindDest, NumHandlers); for (BasicBlock *Handler : Handlers) CatchSwitch->addHandler(Handler); I = CatchSwitch; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CATCHPAD: case bitc::FUNC_CODE_INST_CLEANUPPAD: { // [tok,num,(ty,val)*] // We must have, at minimum, the outer scope and the number of arguments. if (Record.size() < 2) return error("Invalid record"); unsigned Idx = 0; Value *ParentPad = getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); unsigned NumArgOperands = Record[Idx++]; SmallVector Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); Args.push_back(Val); } if (Record.size() != Idx) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_CLEANUPPAD) I = CleanupPadInst::Create(ParentPad, Args); else I = CatchPadInst::Create(ParentPad, Args); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...] // Check magic if ((Record[0] >> 16) == SWITCH_INST_MAGIC) { // "New" SwitchInst format with case ranges. The changes to write this // format were reverted but we still recognize bitcode that uses it. // Hopefully someday we will have support for case ranges and can use // this format again. Type *OpTy = getTypeByID(Record[1]); unsigned ValueBitWidth = cast(OpTy)->getBitWidth(); Value *Cond = getValue(Record, 2, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[3]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = Record[4]; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); unsigned CurIdx = 5; for (unsigned i = 0; i != NumCases; ++i) { SmallVector CaseVals; unsigned NumItems = Record[CurIdx++]; for (unsigned ci = 0; ci != NumItems; ++ci) { bool isSingleNumber = Record[CurIdx++]; APInt Low; unsigned ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; Low = readWideAPInt(makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; if (!isSingleNumber) { ActiveWords = 1; if (ValueBitWidth > 64) ActiveWords = Record[CurIdx++]; APInt High = readWideAPInt( makeArrayRef(&Record[CurIdx], ActiveWords), ValueBitWidth); CurIdx += ActiveWords; // FIXME: It is not clear whether values in the range should be // compared as signed or unsigned values. The partially // implemented changes that used this format in the past used // unsigned comparisons. for ( ; Low.ule(High); ++Low) CaseVals.push_back(ConstantInt::get(Context, Low)); } else CaseVals.push_back(ConstantInt::get(Context, Low)); } BasicBlock *DestBB = getBasicBlock(Record[CurIdx++]); for (SmallVector::iterator cvi = CaseVals.begin(), cve = CaseVals.end(); cvi != cve; ++cvi) SI->addCase(*cvi, DestBB); } I = SI; break; } // Old SwitchInst format without case ranges. if (Record.size() < 3 || (Record.size() & 1) == 0) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Cond = getValue(Record, 1, NextValueNo, OpTy); BasicBlock *Default = getBasicBlock(Record[2]); if (!OpTy || !Cond || !Default) return error("Invalid record"); unsigned NumCases = (Record.size()-3)/2; SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); InstructionList.push_back(SI); for (unsigned i = 0, e = NumCases; i != e; ++i) { ConstantInt *CaseVal = dyn_cast_or_null(getFnValueByID(Record[3+i*2], OpTy)); BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]); if (!CaseVal || !DestBB) { delete SI; return error("Invalid record"); } SI->addCase(CaseVal, DestBB); } I = SI; break; } case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...] if (Record.size() < 2) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Address = getValue(Record, 1, NextValueNo, OpTy); if (!OpTy || !Address) return error("Invalid record"); unsigned NumDests = Record.size()-2; IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests); InstructionList.push_back(IBI); for (unsigned i = 0, e = NumDests; i != e; ++i) { if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) { IBI->addDestination(DestBB); } else { delete IBI; return error("Invalid record"); } } I = IBI; break; } case bitc::FUNC_CODE_INST_INVOKE: { // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...] if (Record.size() < 4) return error("Invalid record"); unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; BasicBlock *NormalBB = getBasicBlock(Record[OpNum++]); BasicBlock *UnwindBB = getBasicBlock(Record[OpNum++]); FunctionType *FTy = nullptr; FunctionType *FullFTy = nullptr; if ((CCInfo >> 13) & 1) { FullFTy = dyn_cast(getFullyStructuredTypeByID(Record[OpNum++])); if (!FullFTy) return error("Explicit invoke type is not a function type"); FTy = cast(flattenPointerTypes(FullFTy)); } Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee, &FullTy)) return error("Invalid record"); PointerType *CalleeTy = dyn_cast(Callee->getType()); if (!CalleeTy) return error("Callee is not a pointer"); if (!FTy) { FullFTy = dyn_cast(cast(FullTy)->getElementType()); if (!FullFTy) return error("Callee is not of pointer to function type"); FTy = cast(flattenPointerTypes(FullFTy)); } else if (getPointerElementFlatType(FullTy) != FTy) return error("Explicit invoke type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Ops; SmallVector ArgsFullTys; for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { Ops.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); ArgsFullTys.push_back(FullFTy->getParamType(i)); if (!Ops.back()) return error("Invalid record"); } if (!FTy->isVarArg()) { if (Record.size() != OpNum) return error("Invalid record"); } else { // Read type/value pairs for varargs params. while (OpNum != Record.size()) { Value *Op; Type *FullTy; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy)) return error("Invalid record"); Ops.push_back(Op); ArgsFullTys.push_back(FullTy); } } I = InvokeInst::Create(FTy, Callee, NormalBB, UnwindBB, Ops, OperandBundles); FullTy = FullFTy->getReturnType(); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast(CallingConv::MaxID & CCInfo)); cast(I)->setAttributes(PAL); propagateByValTypes(cast(I), ArgsFullTys); break; } case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval] unsigned Idx = 0; Value *Val = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, Val)) return error("Invalid record"); I = ResumeInst::Create(Val); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CALLBR: { // CALLBR: [attr, cc, norm, transfs, fty, fnid, args] unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; BasicBlock *DefaultDest = getBasicBlock(Record[OpNum++]); unsigned NumIndirectDests = Record[OpNum++]; SmallVector IndirectDests; for (unsigned i = 0, e = NumIndirectDests; i != e; ++i) IndirectDests.push_back(getBasicBlock(Record[OpNum++])); FunctionType *FTy = nullptr; FunctionType *FullFTy = nullptr; if ((CCInfo >> bitc::CALL_EXPLICIT_TYPE) & 1) { FullFTy = dyn_cast(getFullyStructuredTypeByID(Record[OpNum++])); if (!FullFTy) return error("Explicit call type is not a function type"); FTy = cast(flattenPointerTypes(FullFTy)); } Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee, &FullTy)) return error("Invalid record"); PointerType *OpTy = dyn_cast(Callee->getType()); if (!OpTy) return error("Callee is not a pointer type"); if (!FTy) { FullFTy = dyn_cast(cast(FullTy)->getElementType()); if (!FullFTy) return error("Callee is not of pointer to function type"); FTy = cast(flattenPointerTypes(FullFTy)); } else if (getPointerElementFlatType(FullTy) != FTy) return error("Explicit call type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Args; // Read the fixed params. for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { if (FTy->getParamType(i)->isLabelTy()) Args.push_back(getBasicBlock(Record[OpNum])); else Args.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); if (!Args.back()) return error("Invalid record"); } // Read type/value pairs for varargs params. if (!FTy->isVarArg()) { if (OpNum != Record.size()) return error("Invalid record"); } else { while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Args.push_back(Op); } } I = CallBrInst::Create(FTy, Callee, DefaultDest, IndirectDests, Args, OperandBundles); FullTy = FullFTy->getReturnType(); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast((0x7ff & CCInfo) >> bitc::CALL_CCONV)); cast(I)->setAttributes(PAL); break; } case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE I = new UnreachableInst(Context); InstructionList.push_back(I); break; case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] if (Record.size() < 1 || ((Record.size()-1)&1)) return error("Invalid record"); FullTy = getFullyStructuredTypeByID(Record[0]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2); InstructionList.push_back(PN); for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) { Value *V; // With the new function encoding, it is possible that operands have // negative IDs (for forward references). Use a signed VBR // representation to keep the encoding small. if (UseRelativeIDs) V = getValueSigned(Record, 1+i, NextValueNo, Ty); else V = getValue(Record, 1+i, NextValueNo, Ty); BasicBlock *BB = getBasicBlock(Record[2+i]); if (!V || !BB) return error("Invalid record"); PN->addIncoming(V, BB); } I = PN; break; } case bitc::FUNC_CODE_INST_LANDINGPAD: case bitc::FUNC_CODE_INST_LANDINGPAD_OLD: { // LANDINGPAD: [ty, val, val, num, (id0,val0 ...)?] unsigned Idx = 0; if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD) { if (Record.size() < 3) return error("Invalid record"); } else { IGC_ASSERT(BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD); if (Record.size() < 4) return error("Invalid record"); } FullTy = getFullyStructuredTypeByID(Record[Idx++]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); if (BitCode == bitc::FUNC_CODE_INST_LANDINGPAD_OLD) { Value *PersFn = nullptr; if (getValueTypePair(Record, Idx, NextValueNo, PersFn)) return error("Invalid record"); if (!F->hasPersonalityFn()) F->setPersonalityFn(cast(PersFn)); else if (F->getPersonalityFn() != cast(PersFn)) return error("Personality function mismatch"); } bool IsCleanup = !!Record[Idx++]; unsigned NumClauses = Record[Idx++]; LandingPadInst *LP = LandingPadInst::Create(Ty, NumClauses); LP->setCleanup(IsCleanup); for (unsigned J = 0; J != NumClauses; ++J) { LandingPadInst::ClauseType CT = LandingPadInst::ClauseType(Record[Idx++]); (void)CT; Value *Val; if (getValueTypePair(Record, Idx, NextValueNo, Val)) { delete LP; return error("Invalid record"); } IGC_ASSERT((CT != LandingPadInst::Catch || !isa(Val->getType())) && "Catch clause has a invalid type!"); IGC_ASSERT((CT != LandingPadInst::Filter || isa(Val->getType())) && "Filter clause has invalid type!"); LP->addClause(cast(Val)); } I = LP; InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align] if (Record.size() != 4) return error("Invalid record"); uint64_t AlignRecord = Record[3]; const uint64_t InAllocaMask = uint64_t(1) << 5; const uint64_t ExplicitTypeMask = uint64_t(1) << 6; const uint64_t SwiftErrorMask = uint64_t(1) << 7; const uint64_t FlagMask = InAllocaMask | ExplicitTypeMask | SwiftErrorMask; bool InAlloca = AlignRecord & InAllocaMask; bool SwiftError = AlignRecord & SwiftErrorMask; FullTy = getFullyStructuredTypeByID(Record[0]); Type *Ty = flattenPointerTypes(FullTy); if ((AlignRecord & ExplicitTypeMask) == 0) { auto *PTy = dyn_cast_or_null(Ty); if (!PTy) return error("Old-style alloca with a non-pointer type"); std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); } Type *OpTy = getTypeByID(Record[1]); Value *Size = getFnValueByID(Record[2], OpTy); unsigned Align; if (Error Err = parseAlignmentValue(AlignRecord & ~FlagMask, Align)) { return Err; } if (!Ty || !Size) return error("Invalid record"); // FIXME: Make this an optional field. const DataLayout &DL = TheModule->getDataLayout(); unsigned AS = DL.getAllocaAddrSpace(); AllocaInst *AI = new AllocaInst(Ty, AS, Size, Align); AI->setUsedWithInAlloca(InAlloca); AI->setSwiftError(SwiftError); I = AI; FullTy = PointerType::get(FullTy, AS); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy) || (OpNum + 2 != Record.size() && OpNum + 3 != Record.size())) return error("Invalid record"); if (!isa(Op->getType())) return error("Load operand is not a pointer type"); Type *Ty = nullptr; if (OpNum + 3 == Record.size()) { FullTy = getFullyStructuredTypeByID(Record[OpNum++]); Ty = flattenPointerTypes(FullTy); } else std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Ty, Op, "", Record[OpNum + 1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_LOADATOMIC: { // LOADATOMIC: [opty, op, align, vol, ordering, ssid] unsigned OpNum = 0; Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy) || (OpNum + 4 != Record.size() && OpNum + 5 != Record.size())) return error("Invalid record"); if (!isa(Op->getType())) return error("Load operand is not a pointer type"); Type *Ty = nullptr; if (OpNum + 5 == Record.size()) { FullTy = getFullyStructuredTypeByID(Record[OpNum++]); Ty = flattenPointerTypes(FullTy); } else std::tie(FullTy, Ty) = getPointerElementTypes(FullTy); if (Error Err = typeCheckLoadStoreInst(Ty, Op->getType())) return Err; AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Release || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new LoadInst(Ty, Op, "", Record[OpNum + 1], Align, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STORE: case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol] unsigned OpNum = 0; Value *Val, *Ptr; Type *FullTy; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy) || (BitCode == bitc::FUNC_CODE_INST_STORE ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, getPointerElementFlatType(FullTy), Val)) || OpNum + 2 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum+1], Align); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_STOREATOMIC: case bitc::FUNC_CODE_INST_STOREATOMIC_OLD: { // STOREATOMIC: [ptrty, ptr, val, align, vol, ordering, ssid] unsigned OpNum = 0; Value *Val, *Ptr; Type *FullTy; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy) || !isa(Ptr->getType()) || (BitCode == bitc::FUNC_CODE_INST_STOREATOMIC ? getValueTypePair(Record, OpNum, NextValueNo, Val) : popValue(Record, OpNum, NextValueNo, getPointerElementFlatType(FullTy), Val)) || OpNum + 4 != Record.size()) return error("Invalid record"); if (Error Err = typeCheckLoadStoreInst(Val->getType(), Ptr->getType())) return Err; AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Acquire || Ordering == AtomicOrdering::AcquireRelease) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); if (Ordering != AtomicOrdering::NotAtomic && Record[OpNum] == 0) return error("Invalid record"); unsigned Align; if (Error Err = parseAlignmentValue(Record[OpNum], Align)) return Err; I = new StoreInst(Val, Ptr, Record[OpNum+1], Align, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CMPXCHG_OLD: case bitc::FUNC_CODE_INST_CMPXCHG: { // CMPXCHG:[ptrty, ptr, cmp, new, vol, successordering, ssid, // failureordering?, isweak?] unsigned OpNum = 0; Value *Ptr, *Cmp, *New; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy)) return error("Invalid record"); if (!isa(Ptr->getType())) return error("Cmpxchg operand is not a pointer type"); if (BitCode == bitc::FUNC_CODE_INST_CMPXCHG) { if (getValueTypePair(Record, OpNum, NextValueNo, Cmp, &FullTy)) return error("Invalid record"); } else if (popValue(Record, OpNum, NextValueNo, getPointerElementFlatType(FullTy), Cmp)) return error("Invalid record"); else FullTy = cast(FullTy)->getElementType(); if (popValue(Record, OpNum, NextValueNo, Cmp->getType(), New) || Record.size() < OpNum + 3 || Record.size() > OpNum + 5) return error("Invalid record"); AtomicOrdering SuccessOrdering = getDecodedOrdering(Record[OpNum + 1]); if (SuccessOrdering == AtomicOrdering::NotAtomic || SuccessOrdering == AtomicOrdering::Unordered) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 2]); if (Error Err = typeCheckLoadStoreInst(Cmp->getType(), Ptr->getType())) return Err; AtomicOrdering FailureOrdering; if (Record.size() < 7) FailureOrdering = AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrdering); else FailureOrdering = getDecodedOrdering(Record[OpNum + 3]); I = new AtomicCmpXchgInst(Ptr, Cmp, New, SuccessOrdering, FailureOrdering, SSID); FullTy = StructType::get(Context, {FullTy, Type::getInt1Ty(Context)}); cast(I)->setVolatile(Record[OpNum]); if (Record.size() < 8) { // Before weak cmpxchgs existed, the instruction simply returned the // value loaded from memory, so bitcode files from that era will be // expecting the first component of a modern cmpxchg. CurBB->getInstList().push_back(I); I = ExtractValueInst::Create(I, 0); FullTy = cast(FullTy)->getElementType(0); } else { cast(I)->setWeak(Record[OpNum+4]); } InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_ATOMICRMW: { // ATOMICRMW:[ptrty, ptr, val, op, vol, ordering, ssid] unsigned OpNum = 0; Value *Ptr, *Val; if (getValueTypePair(Record, OpNum, NextValueNo, Ptr, &FullTy) || !isa(Ptr->getType()) || popValue(Record, OpNum, NextValueNo, getPointerElementFlatType(FullTy), Val) || OpNum + 4 != Record.size()) return error("Invalid record"); AtomicRMWInst::BinOp Operation = getDecodedRMWOperation(Record[OpNum]); if (Operation < AtomicRMWInst::FIRST_BINOP || Operation > AtomicRMWInst::LAST_BINOP) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[OpNum + 2]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[OpNum + 3]); I = new AtomicRMWInst(Operation, Ptr, Val, Ordering, SSID); FullTy = getPointerElementFlatType(FullTy); cast(I)->setVolatile(Record[OpNum+1]); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_FENCE: { // FENCE:[ordering, ssid] if (2 != Record.size()) return error("Invalid record"); AtomicOrdering Ordering = getDecodedOrdering(Record[0]); if (Ordering == AtomicOrdering::NotAtomic || Ordering == AtomicOrdering::Unordered || Ordering == AtomicOrdering::Monotonic) return error("Invalid record"); SyncScope::ID SSID = getDecodedSyncScopeID(Record[1]); I = new FenceInst(Context, Ordering, SSID); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_INST_CALL: { // CALL: [paramattrs, cc, fmf, fnty, fnid, arg0, arg1...] if (Record.size() < 3) return error("Invalid record"); unsigned OpNum = 0; AttributeList PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; FastMathFlags FMF; if ((CCInfo >> bitc::CALL_FMF) & 1) { FMF = getDecodedFastMathFlags(Record[OpNum++]); if (!FMF.any()) return error("Fast math flags indicator set for call with no FMF"); } FunctionType *FTy = nullptr; FunctionType *FullFTy = nullptr; if ((CCInfo >> bitc::CALL_EXPLICIT_TYPE) & 1) { FullFTy = dyn_cast(getFullyStructuredTypeByID(Record[OpNum++])); if (!FullFTy) return error("Explicit call type is not a function type"); FTy = cast(flattenPointerTypes(FullFTy)); } Value *Callee; if (getValueTypePair(Record, OpNum, NextValueNo, Callee, &FullTy)) return error("Invalid record"); PointerType *OpTy = dyn_cast(Callee->getType()); if (!OpTy) return error("Callee is not a pointer type"); if (!FTy) { FullFTy = dyn_cast(cast(FullTy)->getElementType()); if (!FullFTy) return error("Callee is not of pointer to function type"); FTy = cast(flattenPointerTypes(FullFTy)); } else if (getPointerElementFlatType(FullTy) != FTy) return error("Explicit call type does not match pointee type of " "callee operand"); if (Record.size() < FTy->getNumParams() + OpNum) return error("Insufficient operands to call"); SmallVector Args; SmallVector ArgsFullTys; // Read the fixed params. for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { if (FTy->getParamType(i)->isLabelTy()) Args.push_back(getBasicBlock(Record[OpNum])); else Args.push_back(getValue(Record, OpNum, NextValueNo, FTy->getParamType(i))); ArgsFullTys.push_back(FullFTy->getParamType(i)); if (!Args.back()) return error("Invalid record"); } // Read type/value pairs for varargs params. if (!FTy->isVarArg()) { if (OpNum != Record.size()) return error("Invalid record"); } else { while (OpNum != Record.size()) { Value *Op; Type *FullTy; if (getValueTypePair(Record, OpNum, NextValueNo, Op, &FullTy)) return error("Invalid record"); Args.push_back(Op); ArgsFullTys.push_back(FullTy); } } I = CallInst::Create(FTy, Callee, Args, OperandBundles); FullTy = FullFTy->getReturnType(); OperandBundles.clear(); InstructionList.push_back(I); cast(I)->setCallingConv( static_cast((0x7ff & CCInfo) >> bitc::CALL_CCONV)); CallInst::TailCallKind TCK = CallInst::TCK_None; if (CCInfo & 1 << bitc::CALL_TAIL) TCK = CallInst::TCK_Tail; if (CCInfo & (1 << bitc::CALL_MUSTTAIL)) TCK = CallInst::TCK_MustTail; if (CCInfo & (1 << bitc::CALL_NOTAIL)) TCK = CallInst::TCK_NoTail; cast(I)->setTailCallKind(TCK); cast(I)->setAttributes(PAL); propagateByValTypes(cast(I), ArgsFullTys); if (FMF.any()) { if (!isa(I)) return error("Fast-math-flags specified for call without " "floating-point scalar or vector return type"); I->setFastMathFlags(FMF); } break; } case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty] if (Record.size() < 3) return error("Invalid record"); Type *OpTy = getTypeByID(Record[0]); Value *Op = getValue(Record, 1, NextValueNo, OpTy); FullTy = getFullyStructuredTypeByID(Record[2]); Type *ResTy = flattenPointerTypes(FullTy); if (!OpTy || !Op || !ResTy) return error("Invalid record"); I = new VAArgInst(Op, ResTy); InstructionList.push_back(I); break; } case bitc::FUNC_CODE_OPERAND_BUNDLE: { // A call or an invoke can be optionally prefixed with some variable // number of operand bundle blocks. These blocks are read into // OperandBundles and consumed at the next call or invoke instruction. if (Record.size() < 1 || Record[0] >= BundleTags.size()) return error("Invalid record"); std::vector Inputs; unsigned OpNum = 1; while (OpNum != Record.size()) { Value *Op; if (getValueTypePair(Record, OpNum, NextValueNo, Op)) return error("Invalid record"); Inputs.push_back(Op); } OperandBundles.emplace_back(BundleTags[Record[0]], std::move(Inputs)); continue; } } // Add instruction to end of current BB. If there is no current BB, reject // this file. if (!CurBB) { I->deleteValue(); return error("Invalid instruction with no BB"); } if (!OperandBundles.empty()) { I->deleteValue(); return error("Operand bundles found with no consumer"); } CurBB->getInstList().push_back(I); // If this was a terminator instruction, move to the next block. if (I->isTerminator()) { ++CurBBNo; CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr; } // Non-void values get registered in the value table for future use. if (I && !I->getType()->isVoidTy()) { if (!FullTy) { FullTy = I->getType(); IGC_ASSERT( !FullTy->isPointerTy() && !isa(FullTy) && !isa(FullTy) && (!isa(FullTy) || FullTy->getVectorElementType()->isFloatingPointTy() || FullTy->getVectorElementType()->isIntegerTy()) && "Structured types must be assigned with corresponding non-opaque " "pointer type"); } IGC_ASSERT(I->getType() == flattenPointerTypes(FullTy) && "Incorrect fully structured type provided for Instruction"); ValueList.assignValue(I, NextValueNo++, FullTy); } } OutOfRecordLoop: if (!OperandBundles.empty()) return error("Operand bundles found with no consumer"); // Check the function list for unresolved values. if (Argument *A = dyn_cast(ValueList.back())) { if (!A->getParent()) { // We found at least one unresolved value. Nuke them all to avoid leaks. for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){ if ((A = dyn_cast_or_null(ValueList[i])) && !A->getParent()) { A->replaceAllUsesWith(UndefValue::get(A->getType())); delete A; } } return error("Never resolved value found in function"); } } // Unexpected unresolved metadata about to be dropped. if (MDLoader->hasFwdRefs()) return error("Invalid function metadata: outgoing forward refs"); // Trim the value list down to the size it was before we parsed this function. ValueList.shrinkTo(ModuleValueListSize); MDLoader->shrinkTo(ModuleMDLoaderSize); std::vector().swap(FunctionBBs); return Error::success(); } /// Find the function body in the bitcode stream Error BitcodeReader::findFunctionInStream( Function *F, DenseMap::iterator DeferredFunctionInfoIterator) { while (DeferredFunctionInfoIterator->second == 0) { // This is the fallback handling for the old format bitcode that // didn't contain the function index in the VST, or when we have // an anonymous function which would not have a VST entry. // Assert that we have one of those two cases. IGC_ASSERT(VSTOffset == 0 || !F->hasName()); // Parse the next body in the stream and set its position in the // DeferredFunctionInfo map. if (Error Err = rememberAndSkipFunctionBodies()) return Err; } return Error::success(); } SyncScope::ID BitcodeReader::getDecodedSyncScopeID(unsigned Val) { if (Val == SyncScope::SingleThread || Val == SyncScope::System) return SyncScope::ID(Val); if (Val >= SSIDs.size()) return SyncScope::System; // Map unknown synchronization scopes to system. return SSIDs[Val]; } //===----------------------------------------------------------------------===// // GVMaterializer implementation //===----------------------------------------------------------------------===// Error BitcodeReader::materialize(GlobalValue *GV) { Function *F = dyn_cast(GV); // If it's not a function or is already material, ignore the request. if (!F || !F->isMaterializable()) return Error::success(); DenseMap::iterator DFII = DeferredFunctionInfo.find(F); IGC_ASSERT(DFII != DeferredFunctionInfo.end() && "Deferred function not found!"); // If its position is recorded as 0, its body is somewhere in the stream // but we haven't seen it yet. if (DFII->second == 0) if (Error Err = findFunctionInStream(F, DFII)) return Err; // Materialize metadata before parsing any function bodies. if (Error Err = materializeMetadata()) return Err; // Move the bit stream to the saved position of the deferred function body. if (Error JumpFailed = Stream.JumpToBit(DFII->second)) return JumpFailed; if (Error Err = parseFunctionBody(F)) return Err; F->setIsMaterializable(false); if (StripDebugInfo) stripDebugInfo(*F); // Upgrade any old intrinsic calls in the function. for (auto &I : UpgradedIntrinsics) { for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) { User *U = *UI; ++UI; if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } } // Update calls to the remangled intrinsics for (auto &I : RemangledIntrinsics) for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end(); UI != UE;) // Don't expect any other users than call sites CallSite(*UI++).setCalledFunction(I.second); // Finish fn->subprogram upgrade for materialized functions. if (DISubprogram *SP = MDLoader->lookupSubprogramForFunction(F)) F->setSubprogram(SP); // Check if the TBAA Metadata are valid, otherwise we will need to strip them. if (!MDLoader->isStrippingTBAA()) { for (auto &I : instructions(F)) { MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa); if (!TBAA || TBAAVerifyHelper.visitTBAAMetadata(I, TBAA)) continue; MDLoader->setStripTBAA(true); stripTBAA(F->getParent()); } } // Bring in any functions that this function forward-referenced via // blockaddresses. return materializeForwardReferencedFunctions(); } Error BitcodeReader::materializeModule() { if (Error Err = materializeMetadata()) return Err; // Promise to materialize all forward references. WillMaterializeAllForwardRefs = true; // Iterate over the module, deserializing any functions that are still on // disk. for (Function &F : *TheModule) { if (Error Err = materialize(&F)) return Err; } // At this point, if there are any function bodies, parse the rest of // the bits in the module past the last function block we have recorded // through either lazy scanning or the VST. if (LastFunctionBlockBit || NextUnreadBit) if (Error Err = parseModule(LastFunctionBlockBit > NextUnreadBit ? LastFunctionBlockBit : NextUnreadBit)) return Err; // Check that all block address forward references got resolved (as we // promised above). if (!BasicBlockFwdRefs.empty()) return error("Never resolved function from blockaddress"); // Upgrade any intrinsic calls that slipped through (should not happen!) and // delete the old functions to clean up. We can't do this unless the entire // module is materialized because there could always be another function body // with calls to the old function. for (auto &I : UpgradedIntrinsics) { for (auto *U : I.first->users()) { if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } if (!I.first->use_empty()) I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } UpgradedIntrinsics.clear(); // Do the same for remangled intrinsics for (auto &I : RemangledIntrinsics) { I.first->replaceAllUsesWith(I.second); I.first->eraseFromParent(); } RemangledIntrinsics.clear(); UpgradeDebugInfo(*TheModule); UpgradeModuleFlags(*TheModule); UpgradeRetainReleaseMarker(*TheModule); return Error::success(); } std::vector BitcodeReader::getIdentifiedStructTypes() const { return IdentifiedStructTypes; } ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader( BitstreamCursor Cursor, StringRef Strtab, ModuleSummaryIndex &TheIndex, StringRef ModulePath, unsigned ModuleId) : BitcodeReaderBase(std::move(Cursor), Strtab), TheIndex(TheIndex), ModulePath(ModulePath), ModuleId(ModuleId) {} void ModuleSummaryIndexBitcodeReader::addThisModule() { TheIndex.addModule(ModulePath, ModuleId); } ModuleSummaryIndex::ModuleInfo * ModuleSummaryIndexBitcodeReader::getThisModule() { return TheIndex.getModule(ModulePath); } std::pair ModuleSummaryIndexBitcodeReader::getValueInfoFromValueId(unsigned ValueId) { auto VGI = ValueIdToValueInfoMap[ValueId]; IGC_ASSERT(VGI.first); return VGI; } void ModuleSummaryIndexBitcodeReader::setValueGUID( uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage, StringRef SourceFileName) { std::string GlobalId = GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName); auto ValueGUID = GlobalValue::getGUID(GlobalId); auto OriginalNameID = ValueGUID; if (GlobalValue::isLocalLinkage(Linkage)) OriginalNameID = GlobalValue::getGUID(ValueName); // UseStrtab is false for legacy summary formats and value names are // created on stack. In that case we save the name in a string saver in // the index so that the value name can be recorded. ValueIdToValueInfoMap[ValueID] = std::make_pair( TheIndex.getOrInsertValueInfo( ValueGUID, UseStrtab ? ValueName : TheIndex.saveString(ValueName)), OriginalNameID); } // Specialized value symbol table parser used when reading module index // blocks where we don't actually create global values. The parsed information // is saved in the bitcode reader for use when later parsing summaries. Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable( uint64_t Offset, DenseMap &ValueIdToLinkageMap) { // With a strtab the VST is not required to parse the summary. if (UseStrtab) return Error::success(); IGC_ASSERT(Offset > 0 && "Expected non-zero VST offset"); Expected MaybeCurrentBit = jumpToValueSymbolTable(Offset, Stream); if (!MaybeCurrentBit) return MaybeCurrentBit.takeError(); uint64_t CurrentBit = MaybeCurrentBit.get(); if (Error Err = Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return Err; SmallVector Record; // Read all the records for this value table. SmallString<128> ValueName; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // Done parsing VST, jump back to wherever we came from. if (Error JumpFailed = Stream.JumpToBit(CurrentBit)) return JumpFailed; return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore (e.g. VST_CODE_BBENTRY records). break; case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] if (convertToString(Record, 1, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; setValueGUID(ValueID, ValueName, Linkage, SourceFileName); ValueName.clear(); break; } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] if (convertToString(Record, 2, ValueName)) return error("Invalid record"); unsigned ValueID = Record[0]; IGC_ASSERT(!SourceFileName.empty()); auto VLI = ValueIdToLinkageMap.find(ValueID); IGC_ASSERT(VLI != ValueIdToLinkageMap.end() && "No linkage found for VST entry?"); auto Linkage = VLI->second; setValueGUID(ValueID, ValueName, Linkage, SourceFileName); ValueName.clear(); break; } case bitc::VST_CODE_COMBINED_ENTRY: { // VST_CODE_COMBINED_ENTRY: [valueid, refguid] unsigned ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; // The "original name", which is the second value of the pair will be // overriden later by a FS_COMBINED_ORIGINAL_NAME in the combined index. ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(RefGUID), RefGUID); break; } } } } // Parse just the blocks needed for building the index out of the module. // At the end of this routine the module Index is populated with a map // from global value id to GlobalValueSummary objects. Error ModuleSummaryIndexBitcodeReader::parseModule() { if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return Err; SmallVector Record; DenseMap ValueIdToLinkageMap; unsigned ValueId = 0; // Read the index for this module. while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::SubBlock: switch (Entry.ID) { default: // Skip unknown content. if (Error Err = Stream.SkipBlock()) return Err; break; case bitc::BLOCKINFO_BLOCK_ID: // Need to parse these to get abbrev ids (e.g. for VST) if (readBlockInfo()) return error("Malformed block"); break; case bitc::VALUE_SYMTAB_BLOCK_ID: // Should have been parsed earlier via VSTOffset, unless there // is no summary section. IGC_ASSERT(((SeenValueSymbolTable && VSTOffset > 0) || !SeenGlobalValSummary) && "Expected early VST parse via VSTOffset record"); if (Error Err = Stream.SkipBlock()) return Err; break; case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID: // Add the module if it is a per-module index (has a source file name). if (!SourceFileName.empty()) addThisModule(); IGC_ASSERT(!SeenValueSymbolTable && "Already read VST when parsing summary block?"); // We might not have a VST if there were no values in the // summary. An empty summary block generated when we are // performing ThinLTO compiles so we don't later invoke // the regular LTO process on them. if (VSTOffset > 0) { if (Error Err = parseValueSymbolTable(VSTOffset, ValueIdToLinkageMap)) return Err; SeenValueSymbolTable = true; } SeenGlobalValSummary = true; if (Error Err = parseEntireSummary(Entry.ID)) return Err; break; case bitc::MODULE_STRTAB_BLOCK_ID: if (Error Err = parseModuleStringTable()) return Err; break; } continue; case BitstreamEntry::Record: { Record.clear(); Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (MaybeBitCode.get()) { default: break; // Default behavior, ignore unknown content. case bitc::MODULE_CODE_VERSION: { if (Error Err = parseVersionRecord(Record).takeError()) return Err; break; } /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] case bitc::MODULE_CODE_SOURCE_FILENAME: { SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); SourceFileName = ValueName.c_str(); break; } /// MODULE_CODE_HASH: [5*i32] case bitc::MODULE_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); auto &Hash = getThisModule()->second.second; int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); Hash[Pos++] = Val; } break; } /// MODULE_CODE_VSTOFFSET: [offset] case bitc::MODULE_CODE_VSTOFFSET: if (Record.size() < 1) return error("Invalid record"); // Note that we subtract 1 here because the offset is relative to one // word before the start of the identification or module block, which // was historically always the start of the regular bitcode header. VSTOffset = Record[0] - 1; break; // v1 GLOBALVAR: [pointer type, isconst, initid, linkage, ...] // v1 FUNCTION: [type, callingconv, isproto, linkage, ...] // v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, ...] // v2: [strtab offset, strtab size, v1] case bitc::MODULE_CODE_GLOBALVAR: case bitc::MODULE_CODE_FUNCTION: case bitc::MODULE_CODE_ALIAS: { StringRef Name; ArrayRef GVRecord; std::tie(Name, GVRecord) = readNameFromStrtab(Record); if (GVRecord.size() <= 3) return error("Invalid record"); uint64_t RawLinkage = GVRecord[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); if (!UseStrtab) { ValueIdToLinkageMap[ValueId++] = Linkage; break; } setValueGUID(ValueId++, Name, Linkage, SourceFileName); break; } } } continue; } } } std::vector ModuleSummaryIndexBitcodeReader::makeRefList(ArrayRef Record) { std::vector Ret; Ret.reserve(Record.size()); for (uint64_t RefValueId : Record) Ret.push_back(getValueInfoFromValueId(RefValueId).first); return Ret; } std::vector ModuleSummaryIndexBitcodeReader::makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile, bool HasRelBF) { std::vector Ret; Ret.reserve(Record.size()); for (unsigned I = 0, E = Record.size(); I != E; ++I) { CalleeInfo::HotnessType Hotness = CalleeInfo::HotnessType::Unknown; uint64_t RelBF = 0; ValueInfo Callee = getValueInfoFromValueId(Record[I]).first; if (IsOldProfileFormat) { I += 1; // Skip old callsitecount field if (HasProfile) I += 1; // Skip old profilecount field } else if (HasProfile) Hotness = static_cast(Record[++I]); else if (HasRelBF) RelBF = Record[++I]; Ret.push_back(FunctionSummary::EdgeTy{Callee, CalleeInfo(Hotness, RelBF)}); } return Ret; } static void parseWholeProgramDevirtResolutionByArg(ArrayRef Record, size_t &Slot, WholeProgramDevirtResolution &Wpd) { uint64_t ArgNum = Record[Slot++]; WholeProgramDevirtResolution::ByArg &B = Wpd.ResByArg[{Record.begin() + Slot, Record.begin() + Slot + ArgNum}]; Slot += (size_t)ArgNum; B.TheKind = static_cast(Record[Slot++]); B.Info = Record[Slot++]; B.Byte = Record[Slot++]; B.Bit = Record[Slot++]; } static void parseWholeProgramDevirtResolution(ArrayRef Record, StringRef Strtab, size_t &Slot, TypeIdSummary &TypeId) { uint64_t Id = Record[Slot++]; WholeProgramDevirtResolution &Wpd = TypeId.WPDRes[Id]; Wpd.TheKind = static_cast(Record[Slot++]); Wpd.SingleImplName = {Strtab.data() + Record[Slot], static_cast(Record[Slot + 1])}; Slot += 2; uint64_t ResByArgNum = Record[Slot++]; for (uint64_t I = 0; I != ResByArgNum; ++I) parseWholeProgramDevirtResolutionByArg(Record, Slot, Wpd); } static void parseTypeIdSummaryRecord(ArrayRef Record, StringRef Strtab, ModuleSummaryIndex &TheIndex) { size_t Slot = 0; TypeIdSummary &TypeId = TheIndex.getOrInsertTypeIdSummary( {Strtab.data() + Record[Slot], static_cast(Record[Slot + 1])}); Slot += 2; TypeId.TTRes.TheKind = static_cast(Record[Slot++]); TypeId.TTRes.SizeM1BitWidth = Record[Slot++]; TypeId.TTRes.AlignLog2 = Record[Slot++]; TypeId.TTRes.SizeM1 = Record[Slot++]; TypeId.TTRes.BitMask = Record[Slot++]; TypeId.TTRes.InlineBits = Record[Slot++]; while (Slot < Record.size()) parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId); } void ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableInfo( ArrayRef Record, size_t &Slot, TypeIdCompatibleVtableInfo &TypeId) { uint64_t Offset = Record[Slot++]; ValueInfo Callee = getValueInfoFromValueId(Record[Slot++]).first; TypeId.push_back({Offset, Callee}); } void ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableSummaryRecord( ArrayRef Record) { size_t Slot = 0; TypeIdCompatibleVtableInfo &TypeId = TheIndex.getOrInsertTypeIdCompatibleVtableSummary( {Strtab.data() + Record[Slot], static_cast(Record[Slot + 1])}); Slot += 2; while (Slot < Record.size()) parseTypeIdCompatibleVtableInfo(Record, Slot, TypeId); } static void setSpecialRefs(std::vector &Refs, unsigned ROCnt, unsigned WOCnt) { // Readonly and writeonly refs are in the end of the refs list. IGC_ASSERT(ROCnt + WOCnt <= Refs.size()); unsigned FirstWORef = Refs.size() - WOCnt; unsigned RefNo = FirstWORef - ROCnt; for (; RefNo < FirstWORef; ++RefNo) Refs[RefNo].setReadOnly(); for (; RefNo < Refs.size(); ++RefNo) Refs[RefNo].setWriteOnly(); } // Eagerly parse the entire summary block. This populates the GlobalValueSummary // objects in the index. Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { if (Error Err = Stream.EnterSubBlock(ID)) return Err; SmallVector Record; // Parse version { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); if (Entry.Kind != BitstreamEntry::Record) return error("Invalid Summary Block: record for version expected"); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); if (MaybeRecord.get() != bitc::FS_VERSION) return error("Invalid Summary Block: version expected"); } const uint64_t Version = Record[0]; const bool IsOldProfileFormat = Version == 1; if (Version < 1 || Version > 7) return error("Invalid summary version " + Twine(Version) + ". Version should be in the range [1-7]."); Record.clear(); // Keep around the last seen summary to be used when we see an optional // "OriginalName" attachement. GlobalValueSummary *LastSeenSummary = nullptr; GlobalValue::GUID LastSeenGUID = 0; // We can expect to see any number of type ID information records before // each function summary records; these variables store the information // collected so far so that it can be used to create the summary object. std::vector PendingTypeTests; std::vector PendingTypeTestAssumeVCalls, PendingTypeCheckedLoadVCalls; std::vector PendingTypeTestAssumeConstVCalls, PendingTypeCheckedLoadConstVCalls; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } // Read a record. The record format depends on whether this // is a per-module index or a combined index file. In the per-module // case the records contain the associated value's ID for correlation // with VST entries. In the combined index the correlation is done // via the bitcode offset of the summary records (which were saved // in the combined index VST entries). The records also contain // information used for ThinLTO renaming and importing. Record.clear(); Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (unsigned BitCode = MaybeBitCode.get()) { default: // Default behavior: ignore. break; case bitc::FS_FLAGS: { // [flags] uint64_t Flags = Record[0]; // Scan flags. IGC_ASSERT(Flags <= 0x1f && "Unexpected bits in flag"); // 1 bit: WithGlobalValueDeadStripping flag. // Set on combined index only. if (Flags & 0x1) TheIndex.setWithGlobalValueDeadStripping(); // 1 bit: SkipModuleByDistributedBackend flag. // Set on combined index only. if (Flags & 0x2) TheIndex.setSkipModuleByDistributedBackend(); // 1 bit: HasSyntheticEntryCounts flag. // Set on combined index only. if (Flags & 0x4) TheIndex.setHasSyntheticEntryCounts(); // 1 bit: DisableSplitLTOUnit flag. // Set on per module indexes. It is up to the client to validate // the consistency of this flag across modules being linked. if (Flags & 0x8) TheIndex.setEnableSplitLTOUnit(); // 1 bit: PartiallySplitLTOUnits flag. // Set on combined index only. if (Flags & 0x10) TheIndex.setPartiallySplitLTOUnits(); break; } case bitc::FS_VALUE_GUID: { // [valueid, refguid] uint64_t ValueID = Record[0]; GlobalValue::GUID RefGUID = Record[1]; ValueIdToValueInfoMap[ValueID] = std::make_pair(TheIndex.getOrInsertValueInfo(RefGUID), RefGUID); break; } // FS_PERMODULE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_PERMODULE_PROFILE: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, // n x (valueid, hotness)] // FS_PERMODULE_RELBF: [valueid, flags, instcount, fflags, numrefs, // numrefs x valueid, // n x (valueid, relblockfreq)] case bitc::FS_PERMODULE: case bitc::FS_PERMODULE_RELBF: case bitc::FS_PERMODULE_PROFILE: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned InstCount = Record[2]; uint64_t RawFunFlags = 0; unsigned NumRefs = Record[3]; unsigned NumRORefs = 0, NumWORefs = 0; int RefListStartIndex = 4; if (Version >= 4) { RawFunFlags = Record[3]; NumRefs = Record[4]; RefListStartIndex = 5; if (Version >= 5) { NumRORefs = Record[5]; RefListStartIndex = 6; if (Version >= 7) { NumWORefs = Record[6]; RefListStartIndex = 7; } } } auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_PERMODULE_PROFILE); bool HasRelBF = (BitCode == bitc::FS_PERMODULE_RELBF); std::vector Calls = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile, HasRelBF); setSpecialRefs(Refs, NumRORefs, NumWORefs); auto FS = llvm::make_unique( Flags, InstCount, getDecodedFFlags(RawFunFlags), /*EntryCount=*/0, std::move(Refs), std::move(Calls), std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeCheckedLoadConstVCalls)); PendingTypeTests.clear(); PendingTypeTestAssumeVCalls.clear(); PendingTypeCheckedLoadVCalls.clear(); PendingTypeTestAssumeConstVCalls.clear(); PendingTypeCheckedLoadConstVCalls.clear(); auto VIAndOriginalGUID = getValueInfoFromValueId(ValueID); FS->setModulePath(getThisModule()->first()); FS->setOriginalName(VIAndOriginalGUID.second); TheIndex.addGlobalValueSummary(VIAndOriginalGUID.first, std::move(FS)); break; } // FS_ALIAS: [valueid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_PERMODULE entries, as // they expect all aliasee summaries to be available. case bitc::FS_ALIAS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned AliaseeID = Record[2]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = llvm::make_unique(Flags); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. AS->setModulePath(getThisModule()->first()); auto AliaseeVI = getValueInfoFromValueId(AliaseeID).first; auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeVI, ModulePath); if (!AliaseeInModule) return error("Alias expects aliasee summary to be parsed"); AS->setAliasee(AliaseeVI, AliaseeInModule); auto GUID = getValueInfoFromValueId(ValueID); AS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(AS)); break; } // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags, n x valueid] case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned RefArrayStart = 2; GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false, /* WriteOnly */ false); auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[2]); RefArrayStart = 3; } std::vector Refs = makeRefList(ArrayRef(Record).slice(RefArrayStart)); auto FS = llvm::make_unique(Flags, GVF, std::move(Refs)); FS->setModulePath(getThisModule()->first()); auto GUID = getValueInfoFromValueId(ValueID); FS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(FS)); break; } // FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags, // numrefs, numrefs x valueid, // n x (valueid, offset)] case bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; GlobalVarSummary::GVarFlags GVF = getDecodedGVarFlags(Record[2]); unsigned NumRefs = Record[3]; unsigned RefListStartIndex = 4; unsigned VTableListStartIndex = RefListStartIndex + NumRefs; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); VTableFuncList VTableFuncs; for (unsigned I = VTableListStartIndex, E = Record.size(); I != E; ++I) { ValueInfo Callee = getValueInfoFromValueId(Record[I]).first; uint64_t Offset = Record[++I]; VTableFuncs.push_back({Callee, Offset}); } auto VS = llvm::make_unique(Flags, GVF, std::move(Refs)); VS->setModulePath(getThisModule()->first()); VS->setVTableFuncs(VTableFuncs); auto GUID = getValueInfoFromValueId(ValueID); VS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(VS)); break; } // FS_COMBINED: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid)] // FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, fflags, numrefs, // numrefs x valueid, n x (valueid, hotness)] case bitc::FS_COMBINED: case bitc::FS_COMBINED_PROFILE: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned InstCount = Record[3]; uint64_t RawFunFlags = 0; uint64_t EntryCount = 0; unsigned NumRefs = Record[4]; unsigned NumRORefs = 0, NumWORefs = 0; int RefListStartIndex = 5; if (Version >= 4) { RawFunFlags = Record[4]; RefListStartIndex = 6; size_t NumRefsIndex = 5; if (Version >= 5) { unsigned NumRORefsOffset = 1; RefListStartIndex = 7; if (Version >= 6) { NumRefsIndex = 6; EntryCount = Record[5]; RefListStartIndex = 8; if (Version >= 7) { RefListStartIndex = 9; NumWORefs = Record[8]; NumRORefsOffset = 2; } } NumRORefs = Record[RefListStartIndex - NumRORefsOffset]; } NumRefs = Record[NumRefsIndex]; } auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; IGC_ASSERT(Record.size() >= RefListStartIndex + NumRefs && "Record size inconsistent with number of references"); std::vector Refs = makeRefList( ArrayRef(Record).slice(RefListStartIndex, NumRefs)); bool HasProfile = (BitCode == bitc::FS_COMBINED_PROFILE); std::vector Edges = makeCallList( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile, false); ValueInfo VI = getValueInfoFromValueId(ValueID).first; setSpecialRefs(Refs, NumRORefs, NumWORefs); auto FS = llvm::make_unique( Flags, InstCount, getDecodedFFlags(RawFunFlags), EntryCount, std::move(Refs), std::move(Edges), std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeCheckedLoadConstVCalls)); PendingTypeTests.clear(); PendingTypeTestAssumeVCalls.clear(); PendingTypeCheckedLoadVCalls.clear(); PendingTypeTestAssumeConstVCalls.clear(); PendingTypeCheckedLoadConstVCalls.clear(); LastSeenSummary = FS.get(); LastSeenGUID = VI.getGUID(); FS->setModulePath(ModuleIdMap[ModuleId]); TheIndex.addGlobalValueSummary(VI, std::move(FS)); break; } // FS_COMBINED_ALIAS: [valueid, modid, flags, valueid] // Aliases must be emitted (and parsed) after all FS_COMBINED entries, as // they expect all aliasee summaries to be available. case bitc::FS_COMBINED_ALIAS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned AliaseeValueId = Record[3]; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); auto AS = llvm::make_unique(Flags); LastSeenSummary = AS.get(); AS->setModulePath(ModuleIdMap[ModuleId]); auto AliaseeVI = getValueInfoFromValueId(AliaseeValueId).first; auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeVI, AS->modulePath()); AS->setAliasee(AliaseeVI, AliaseeInModule); ValueInfo VI = getValueInfoFromValueId(ValueID).first; LastSeenGUID = VI.getGUID(); TheIndex.addGlobalValueSummary(VI, std::move(AS)); break; } // FS_COMBINED_GLOBALVAR_INIT_REFS: [valueid, modid, flags, n x valueid] case bitc::FS_COMBINED_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned RefArrayStart = 3; GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false, /* WriteOnly */ false); auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[3]); RefArrayStart = 4; } std::vector Refs = makeRefList(ArrayRef(Record).slice(RefArrayStart)); auto FS = llvm::make_unique(Flags, GVF, std::move(Refs)); LastSeenSummary = FS.get(); FS->setModulePath(ModuleIdMap[ModuleId]); ValueInfo VI = getValueInfoFromValueId(ValueID).first; LastSeenGUID = VI.getGUID(); TheIndex.addGlobalValueSummary(VI, std::move(FS)); break; } // FS_COMBINED_ORIGINAL_NAME: [original_name] case bitc::FS_COMBINED_ORIGINAL_NAME: { uint64_t OriginalName = Record[0]; if (!LastSeenSummary) return error("Name attachment that does not follow a combined record"); LastSeenSummary->setOriginalName(OriginalName); TheIndex.addOriginalName(LastSeenGUID, OriginalName); // Reset the LastSeenSummary LastSeenSummary = nullptr; LastSeenGUID = 0; break; } case bitc::FS_TYPE_TESTS: IGC_ASSERT(PendingTypeTests.empty()); PendingTypeTests.insert(PendingTypeTests.end(), Record.begin(), Record.end()); break; case bitc::FS_TYPE_TEST_ASSUME_VCALLS: IGC_ASSERT(PendingTypeTestAssumeVCalls.empty()); for (unsigned I = 0; I != Record.size(); I += 2) PendingTypeTestAssumeVCalls.push_back({Record[I], Record[I+1]}); break; case bitc::FS_TYPE_CHECKED_LOAD_VCALLS: IGC_ASSERT(PendingTypeCheckedLoadVCalls.empty()); for (unsigned I = 0; I != Record.size(); I += 2) PendingTypeCheckedLoadVCalls.push_back({Record[I], Record[I+1]}); break; case bitc::FS_TYPE_TEST_ASSUME_CONST_VCALL: PendingTypeTestAssumeConstVCalls.push_back( {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; case bitc::FS_TYPE_CHECKED_LOAD_CONST_VCALL: PendingTypeCheckedLoadConstVCalls.push_back( {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; case bitc::FS_CFI_FUNCTION_DEFS: { std::set &CfiFunctionDefs = TheIndex.cfiFunctionDefs(); for (unsigned I = 0; I != Record.size(); I += 2) CfiFunctionDefs.insert( {Strtab.data() + Record[I], static_cast(Record[I + 1])}); break; } case bitc::FS_CFI_FUNCTION_DECLS: { std::set &CfiFunctionDecls = TheIndex.cfiFunctionDecls(); for (unsigned I = 0; I != Record.size(); I += 2) CfiFunctionDecls.insert( {Strtab.data() + Record[I], static_cast(Record[I + 1])}); break; } case bitc::FS_TYPE_ID: parseTypeIdSummaryRecord(Record, Strtab, TheIndex); break; case bitc::FS_TYPE_ID_METADATA: parseTypeIdCompatibleVtableSummaryRecord(Record); break; } } llvm_unreachable("Exit infinite loop"); } // Parse the module string table block into the Index. // This populates the ModulePathStringTable map in the index. Error ModuleSummaryIndexBitcodeReader::parseModuleStringTable() { if (Error Err = Stream.EnterSubBlock(bitc::MODULE_STRTAB_BLOCK_ID)) return Err; SmallVector Record; SmallString<128> ModulePath; ModuleSummaryIndex::ModuleInfo *LastSeenModule = nullptr; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: // The interesting case. break; } Record.clear(); Expected MaybeRecord = Stream.readRecord(Entry.ID, Record); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; case bitc::MST_CODE_ENTRY: { // MST_ENTRY: [modid, namechar x N] uint64_t ModuleId = Record[0]; if (convertToString(Record, 1, ModulePath)) return error("Invalid record"); LastSeenModule = TheIndex.addModule(ModulePath, ModuleId); ModuleIdMap[ModuleId] = LastSeenModule->first(); ModulePath.clear(); break; } /// MST_CODE_HASH: [5*i32] case bitc::MST_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); if (!LastSeenModule) return error("Invalid hash that does not follow a module path"); int Pos = 0; for (auto &Val : Record) { IGC_ASSERT(!(Val >> 32) && "Unexpected high bits set"); LastSeenModule->second.second[Pos++] = Val; } // Reset LastSeenModule to avoid overriding the hash unexpectedly. LastSeenModule = nullptr; break; } } } llvm_unreachable("Exit infinite loop"); } namespace upgrader { // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. class BitcodeErrorCategoryType : public std::error_category { const char *name() const noexcept override { return "llvm.bitcode"; } std::string message(int IE) const override { BitcodeError E = static_cast(IE); switch (E) { case BitcodeError::CorruptedBitcode: return "Corrupted bitcode"; } llvm_unreachable("Unknown error type!"); } }; static ManagedStatic ErrorCategory; const std::error_category &BitcodeErrorCategory() { return *ErrorCategory; } static Expected readBlobInRecord(BitstreamCursor &Stream, unsigned Block, unsigned RecordID) { if (Error Err = Stream.EnterSubBlock(Block)) return std::move(Err); StringRef Strtab; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: return Strtab; case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: if (Error Err = Stream.SkipBlock()) return std::move(Err); break; case BitstreamEntry::Record: StringRef Blob; SmallVector Record; Expected MaybeRecord = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecord) return MaybeRecord.takeError(); if (MaybeRecord.get() == RecordID) Strtab = Blob; break; } } } //===----------------------------------------------------------------------===// // External interface //===----------------------------------------------------------------------===// Expected> getBitcodeModuleList(MemoryBufferRef Buffer) { auto FOrErr = upgrader::getBitcodeFileContents(Buffer); if (!FOrErr) return FOrErr.takeError(); return std::move(FOrErr->Mods); } Expected getBitcodeFileContents(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); BitstreamCursor &Stream = *StreamOrErr; BitcodeFileContents F; while (true) { uint64_t BCBegin = Stream.getCurrentByteNo(); // We may be consuming bitcode from a client that leaves garbage at the end // of the bitcode stream. If we are close enough to // the end that there cannot possibly be another module, stop looking. if (BCBegin + 8 >= Stream.getBitcodeBytes().size()) return F; Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::EndBlock: case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::SubBlock: { uint64_t IdentificationBit = -1ull; if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) { IdentificationBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Error Err = Stream.SkipBlock()) return std::move(Err); { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); Entry = MaybeEntry.get(); } if (Entry.Kind != BitstreamEntry::SubBlock || Entry.ID != bitc::MODULE_BLOCK_ID) return error("Malformed block"); } if (Entry.ID == bitc::MODULE_BLOCK_ID) { uint64_t ModuleBit = Stream.GetCurrentBitNo() - BCBegin * 8; if (Error Err = Stream.SkipBlock()) return std::move(Err); F.Mods.push_back({Stream.getBitcodeBytes().slice( BCBegin, Stream.getCurrentByteNo() - BCBegin), Buffer.getBufferIdentifier(), IdentificationBit, ModuleBit}); continue; } if (Entry.ID == bitc::STRTAB_BLOCK_ID) { Expected Strtab = readBlobInRecord(Stream, bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB); if (!Strtab) return Strtab.takeError(); // This string table is used by every preceding bitcode module that does // not have its own string table. A bitcode file may have multiple // string tables if it was created by binary concatenation, for example // with "llvm-cat -b". for (auto I = F.Mods.rbegin(), E = F.Mods.rend(); I != E; ++I) { if (!I->Strtab.empty()) break; I->Strtab = *Strtab; } // Similarly, the string table is used by every preceding symbol table; // normally there will be just one unless the bitcode file was created // by binary concatenation. if (!F.Symtab.empty() && F.StrtabForSymtab.empty()) F.StrtabForSymtab = *Strtab; continue; } if (Entry.ID == bitc::SYMTAB_BLOCK_ID) { Expected SymtabOrErr = readBlobInRecord(Stream, bitc::SYMTAB_BLOCK_ID, bitc::SYMTAB_BLOB); if (!SymtabOrErr) return SymtabOrErr.takeError(); // We can expect the bitcode file to have multiple symbol tables if it // was created by binary concatenation. In that case we silently // ignore any subsequent symbol tables, which is fine because this is a // low level function. The client is expected to notice that the number // of modules in the symbol table does not match the number of modules // in the input file and regenerate the symbol table. if (F.Symtab.empty()) F.Symtab = *SymtabOrErr; continue; } if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; } case BitstreamEntry::Record: if (Expected StreamFailed = Stream.skipRecord(Entry.ID)) continue; else return StreamFailed.takeError(); } } } /// Get a lazy one-at-time loading module from bitcode. /// /// This isn't always used in a lazy context. In particular, it's also used by /// \a parseModule(). If this is truly lazy, then we need to eagerly pull /// in forward-referenced functions from block address references. /// /// \param[in] MaterializeAll Set to \c true if we should materialize /// everything. Expected> BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting) { BitstreamCursor Stream(Buffer); std::string ProducerIdentification; if (IdentificationBit != -1ull) { if (Error JumpFailed = Stream.JumpToBit(IdentificationBit)) return std::move(JumpFailed); Expected ProducerIdentificationOrErr = readIdentificationBlock(Stream); if (!ProducerIdentificationOrErr) return ProducerIdentificationOrErr.takeError(); ProducerIdentification = *ProducerIdentificationOrErr; } if (Error JumpFailed = Stream.JumpToBit(ModuleBit)) return std::move(JumpFailed); auto *R = new BitcodeReader(std::move(Stream), Strtab, ProducerIdentification, Context); std::unique_ptr M = llvm::make_unique(ModuleIdentifier, Context); M->setMaterializer(R); // Delay parsing Metadata if ShouldLazyLoadMetadata is true. if (Error Err = R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata, IsImporting)) return std::move(Err); if (MaterializeAll) { // Read in the entire module, and destroy the BitcodeReader. if (Error Err = M->materializeAll()) return std::move(Err); } else { // Resolve forward references from blockaddresses. if (Error Err = R->materializeForwardReferencedFunctions()) return std::move(Err); } return std::move(M); } Expected> BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { return getModuleImpl(Context, false, ShouldLazyLoadMetadata, IsImporting); } // Parse the specified bitcode buffer and merge the index into CombinedIndex. // We don't use ModuleIdentifier here because the client may need to control the // module path used in the combined summary (e.g. when reading summaries for // regular LTO modules). Error BitcodeModule::readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, uint64_t ModuleId) { BitstreamCursor Stream(Buffer); if (Error JumpFailed = Stream.JumpToBit(ModuleBit)) return JumpFailed; ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, CombinedIndex, ModulePath, ModuleId); return R.parseModule(); } // Parse the specified bitcode buffer, returning the function info index. Expected> BitcodeModule::getSummary() { BitstreamCursor Stream(Buffer); if (Error JumpFailed = Stream.JumpToBit(ModuleBit)) return std::move(JumpFailed); auto Index = llvm::make_unique(/*HaveGVs=*/false); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, *Index, ModuleIdentifier, 0); if (Error Err = R.parseModule()) return std::move(Err); return std::move(Index); } static Expected getEnableSplitLTOUnitFlag(BitstreamCursor &Stream, unsigned ID) { if (Error Err = Stream.EnterSubBlock(ID)) return std::move(Err); SmallVector Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: // If no flags record found, conservatively return true to mimic // behavior before this flag was added. return true; case BitstreamEntry::Record: // The interesting case. break; } // Look for the FS_FLAGS record. Record.clear(); Expected MaybeBitCode = Stream.readRecord(Entry.ID, Record); if (!MaybeBitCode) return MaybeBitCode.takeError(); switch (MaybeBitCode.get()) { default: // Default behavior: ignore. break; case bitc::FS_FLAGS: { // [flags] uint64_t Flags = Record[0]; // Scan flags. IGC_ASSERT(Flags <= 0x1f && "Unexpected bits in flag"); return Flags & 0x8; } } } llvm_unreachable("Exit infinite loop"); } // Check if the given bitcode buffer contains a global value summary block. Expected BitcodeModule::getLTOInfo() { BitstreamCursor Stream(Buffer); if (Error JumpFailed = Stream.JumpToBit(ModuleBit)) return std::move(JumpFailed); if (Error Err = Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return std::move(Err); while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false, /*EnableSplitLTOUnit=*/false}; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) { Expected EnableSplitLTOUnit = getEnableSplitLTOUnitFlag(Stream, Entry.ID); if (!EnableSplitLTOUnit) return EnableSplitLTOUnit.takeError(); return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true, *EnableSplitLTOUnit}; } if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) { Expected EnableSplitLTOUnit = getEnableSplitLTOUnitFlag(Stream, Entry.ID); if (!EnableSplitLTOUnit) return EnableSplitLTOUnit.takeError(); return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true, *EnableSplitLTOUnit}; } // Ignore other sub-blocks. if (Error Err = Stream.SkipBlock()) return std::move(Err); continue; case BitstreamEntry::Record: if (Expected StreamFailed = Stream.skipRecord(Entry.ID)) continue; else return StreamFailed.takeError(); } } } static Expected getSingleModule(MemoryBufferRef Buffer) { Expected> MsOrErr = upgrader::getBitcodeModuleList(Buffer); if (!MsOrErr) return MsOrErr.takeError(); if (MsOrErr->size() != 1) return error("Expected a single module"); return (*MsOrErr)[0]; } Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLazyModule(Context, ShouldLazyLoadMetadata, IsImporting); } Expected> getOwningLazyBitcodeModule( std::unique_ptr &&Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) { auto MOrErr = upgrader::getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata, IsImporting); if (MOrErr) (*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer)); return MOrErr; } Expected> BitcodeModule::parseModule(LLVMContext &Context) { return getModuleImpl(Context, true, false, false); // TODO: Restore the use-lists to the in-memory state when the bitcode was // written. We must defer until the Module has been fully materialized. } Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->parseModule(Context); } Expected getBitcodeTargetTriple(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readTriple(*StreamOrErr); } Expected isBitcodeContainingObjCCategory(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return hasObjCCategory(*StreamOrErr); } Expected getBitcodeProducerString(MemoryBufferRef Buffer) { Expected StreamOrErr = initStream(Buffer); if (!StreamOrErr) return StreamOrErr.takeError(); return readIdentificationCode(*StreamOrErr); } Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, uint64_t ModuleId) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->readSummary(CombinedIndex, BM->getModuleIdentifier(), ModuleId); } Expected> getModuleSummaryIndex(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getSummary(); } Expected getBitcodeLTOInfo(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); return BM->getLTOInfo(); } Expected> getModuleSummaryIndexForFile(StringRef Path, bool IgnoreEmptyThinLTOIndexFile) { ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path); if (!FileOrErr) return errorCodeToError(FileOrErr.getError()); if (IgnoreEmptyThinLTOIndexFile && !(*FileOrErr)->getBufferSize()) return nullptr; return upgrader::getModuleSummaryIndex(**FileOrErr); } }intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm9/BitcodeReader.h000066400000000000000000000223431363533017100272540ustar00rootroot00000000000000//===- llvm/Bitcode/BitcodeReader.h - Bitcode reader ------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This header defines interfaces to read LLVM bitcode files/streams. // //===----------------------------------------------------------------------===// #ifndef __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #define __DRIVERINTERFACE_UPGRADER_BITCODE_READER_H__ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitCodes.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" #include #include #include #include #include namespace upgrader { using namespace llvm; struct BitcodeFileContents; /// Basic information extracted from a bitcode module to be used for LTO. struct BitcodeLTOInfo { bool IsThinLTO; bool HasSummary; bool EnableSplitLTOUnit; }; /// Represents a module in a bitcode file. class BitcodeModule { // This covers the identification (if present) and module blocks. ArrayRef Buffer; StringRef ModuleIdentifier; // The string table used to interpret this module. StringRef Strtab; // The bitstream location of the IDENTIFICATION_BLOCK. uint64_t IdentificationBit; // The bitstream location of this module's MODULE_BLOCK. uint64_t ModuleBit; BitcodeModule(ArrayRef Buffer, StringRef ModuleIdentifier, uint64_t IdentificationBit, uint64_t ModuleBit) : Buffer(Buffer), ModuleIdentifier(ModuleIdentifier), IdentificationBit(IdentificationBit), ModuleBit(ModuleBit) {} // Calls the ctor. friend Expected getBitcodeFileContents(MemoryBufferRef Buffer); Expected> getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool ShouldLazyLoadMetadata, bool IsImporting); public: StringRef getBuffer() const { return StringRef((const char *)Buffer.begin(), Buffer.size()); } StringRef getStrtab() const { return Strtab; } StringRef getModuleIdentifier() const { return ModuleIdentifier; } /// Read the bitcode module and prepare for lazy deserialization of function /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well. /// If IsImporting is true, this module is being parsed for ThinLTO /// importing into another module. Expected> getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting); /// Read the entire bitcode module and return it. Expected> parseModule(LLVMContext &Context); /// Returns information about the module to be used for LTO: whether to /// compile with ThinLTO, and whether it has a summary. Expected getLTOInfo(); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getSummary(); /// Parse the specified bitcode buffer and merge its module summary index /// into CombinedIndex. Error readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, uint64_t ModuleId); }; struct BitcodeFileContents { std::vector Mods; StringRef Symtab, StrtabForSymtab; }; /// Returns the contents of a bitcode file. This includes the raw contents of /// the symbol table embedded in the bitcode file. Clients which require a /// symbol table should prefer to use irsymtab::read instead of this function /// because it creates a reader for the irsymtab and handles upgrading bitcode /// files without a symbol table or with an old symbol table. Expected getBitcodeFileContents(MemoryBufferRef Buffer); /// Returns a list of modules in the specified bitcode buffer. Expected> getBitcodeModuleList(MemoryBufferRef Buffer); /// Read the header of the specified bitcode buffer and prepare for lazy /// deserialization of function bodies. If ShouldLazyLoadMetadata is true, /// lazily load metadata as well. If IsImporting is true, this module is /// being parsed for ThinLTO importing into another module. Expected> getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, bool ShouldLazyLoadMetadata = false, bool IsImporting = false); Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); #if 0 /// Returns LTO information for the specified bitcode file. Expected getBitcodeLTOInfo(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getModuleSummaryIndex(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer and merge the index into CombinedIndex. Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, uint64_t ModuleId); /// Parse the module summary index out of an IR file and return the module /// summary index object if found, or an empty summary if not. If Path refers /// to an empty file and IgnoreEmptyThinLTOIndexFile is true, then /// this function will return nullptr. Expected> getModuleSummaryIndexForFile(StringRef Path, bool IgnoreEmptyThinLTOIndexFile = false); /// isBitcodeWrapper - Return true if the given bytes are the magic bytes /// for an LLVM IR bitcode wrapper. inline bool isBitcodeWrapper(const unsigned char *BufPtr, const unsigned char *BufEnd) { // See if you can find the hidden message in the magic bytes :-). // (Hint: it's a little-endian encoding.) return BufPtr != BufEnd && BufPtr[0] == 0xDE && BufPtr[1] == 0xC0 && BufPtr[2] == 0x17 && BufPtr[3] == 0x0B; } /// isRawBitcode - Return true if the given bytes are the magic bytes for /// raw LLVM IR bitcode (without a wrapper). inline bool isRawBitcode(const unsigned char *BufPtr, const unsigned char *BufEnd) { // These bytes sort of have a hidden message, but it's not in // little-endian this time, and it's a little redundant. return BufPtr != BufEnd && BufPtr[0] == 'B' && BufPtr[1] == 'C' && BufPtr[2] == 0xc0 && BufPtr[3] == 0xde; } /// isBitcode - Return true if the given bytes are the magic bytes for /// LLVM IR bitcode, either with or without a wrapper. inline bool isBitcode(const unsigned char *BufPtr, const unsigned char *BufEnd) { return isBitcodeWrapper(BufPtr, BufEnd) || isRawBitcode(BufPtr, BufEnd); } /// SkipBitcodeWrapperHeader - Some systems wrap bc files with a special /// header for padding or other reasons. The format of this header is: /// /// struct bc_header { /// uint32_t Magic; // 0x0B17C0DE /// uint32_t Version; // Version, currently always 0. /// uint32_t BitcodeOffset; // Offset to traditional bitcode file. /// uint32_t BitcodeSize; // Size of traditional bitcode file. /// ... potentially other gunk ... /// }; /// /// This function is called when we find a file with a matching magic number. /// In this case, skip down to the subsection of the file that is actually a /// BC file. /// If 'VerifyBufferSize' is true, check that the buffer is large enough to /// contain the whole bitcode file. inline bool SkipBitcodeWrapperHeader(const unsigned char *&BufPtr, const unsigned char *&BufEnd, bool VerifyBufferSize) { // Must contain the offset and size field! if (unsigned(BufEnd - BufPtr) < BWH_SizeField + 4) return true; unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]); unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]); uint64_t BitcodeOffsetEnd = (uint64_t)Offset + (uint64_t)Size; // Verify that Offset+Size fits in the file. if (VerifyBufferSize && BitcodeOffsetEnd > uint64_t(BufEnd-BufPtr)) return true; BufPtr += Offset; BufEnd = BufPtr+Size; return false; } const std::error_category &BitcodeErrorCategory(); enum class BitcodeError { CorruptedBitcode = 1 }; inline std::error_code make_error_code(BitcodeError E) { return std::error_code(static_cast(E), BitcodeErrorCategory()); } #endif } // end namespace llvm #endif // LLVM_BITCODE_BITCODEREADER_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm9/MetadataLoader.h000066400000000000000000000051341363533017100274260ustar00rootroot00000000000000//===-- Bitcode/Reader/MetadataLoader.h - Load Metadatas -------*- C++ -*-====// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This class handles loading Metadatas. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_METADATALOADER_H #define LLVM_LIB_BITCODE_READER_METADATALOADER_H #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Error.h" #include #include namespace llvm { class BitcodeReaderValueList; class BitstreamCursor; class DISubprogram; class Error; class Function; class Instruction; class Metadata; class MDNode; class Module; class Type; /// Helper class that handles loading Metadatas and keeping them available. class MetadataLoader { class MetadataLoaderImpl; std::unique_ptr Pimpl; Error parseMetadata(bool ModuleLevel); public: ~MetadataLoader(); MetadataLoader(BitstreamCursor &Stream, Module &TheModule, BitcodeReaderValueList &ValueList, bool IsImporting, std::function getTypeByID); MetadataLoader &operator=(MetadataLoader &&); MetadataLoader(MetadataLoader &&); // Parse a module metadata block Error parseModuleMetadata() { return parseMetadata(true); } // Parse a function metadata block Error parseFunctionMetadata() { return parseMetadata(false); } /// Set the mode to strip TBAA metadata on load. void setStripTBAA(bool StripTBAA = true); /// Return true if the Loader is stripping TBAA metadata. bool isStrippingTBAA(); // Return true there are remaining unresolved forward references. bool hasFwdRefs() const; /// Return the given metadata, creating a replaceable forward reference if /// necessary. Metadata *getMetadataFwdRefOrLoad(unsigned Idx); /// Return the DISubprogram metadata for a Function if any, null otherwise. DISubprogram *lookupSubprogramForFunction(Function *F); /// Parse a `METADATA_ATTACHMENT` block for a function. Error parseMetadataAttachment( Function &F, const SmallVectorImpl &InstructionList); /// Parse a `METADATA_KIND` block for the current module. Error parseMetadataKinds(); unsigned size() const; void shrinkTo(unsigned N); /// Perform bitcode upgrades on llvm.dbg.* calls. void upgradeDebugIntrinsics(Function &F); }; } #endif // LLVM_LIB_BITCODE_READER_METADATALOADER_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm9/Upgrader.cpp000066400000000000000000000043221363533017100266610ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #pragma warning(disable:4141) #pragma warning(disable:4146) #pragma warning(disable:4244) #pragma warning(disable:4624) #pragma warning(disable:4800) #include "Upgrader.h" #include "common/LLVMWarningsPush.hpp" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include #include #include "common/LLVMWarningsPop.hpp" using namespace llvm; std::unique_ptr upgrader::upgradeBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { auto ErrM = upgrader::parseBitcodeFile(Buffer, Context); Module *M = ErrM.get().get(); if (!M) return nullptr; SmallVector Buf; Buf.reserve(1024*1024); raw_svector_ostream OS(Buf); WriteBitcodeToFile(*M, OS); return MemoryBuffer::getMemBufferCopy(OS.str()); } Expected> upgrader::upgradeAndParseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context) { return upgrader::parseBitcodeFile(Buffer, Context); } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm9/Upgrader.h000066400000000000000000000036741363533017100263370ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ // vim:ts=2:sw=2:et: #ifndef __DRIVERINTERFACE_UPGRADER_H__ #define __DRIVERINTERFACE_UPGRADER_H__ #include "common/LLVMWarningsPush.hpp" #include #include #include #include #include "common/LLVMWarningsPop.hpp" namespace upgrader { llvm::Expected> parseBitcodeFile(llvm::MemoryBufferRef Buffer, llvm::LLVMContext &Context); std::unique_ptr upgradeBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); llvm::Expected> upgradeAndParseBitcodeFile(llvm::MemoryBufferRef, llvm::LLVMContext &); } // End upgrader namespace #endif // __DRIVERINTERFACE_UPGRADER_H__ intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/Upgrader/llvm9/ValueList.h000066400000000000000000000065411363533017100264720ustar00rootroot00000000000000//===-- Bitcode/Reader/ValueList.h - Number values --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This class gives values and types Unique ID's. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_BITCODE_READER_VALUELIST_H #define LLVM_LIB_BITCODE_READER_VALUELIST_H #include "llvm/IR/ValueHandle.h" #include #include #include "Probe.h" namespace llvm { class Constant; class LLVMContext; class Type; class Value; class BitcodeReaderValueList { std::vector ValuePtrs; /// Struct containing fully-specified copies of the type of each /// value. When pointers are opaque, this will be contain non-opaque /// variants so that restructuring instructions can determine their /// type correctly even if being loaded from old bitcode where some /// types are implicit. std::vector FullTypes; /// As we resolve forward-referenced constants, we add information about them /// to this vector. This allows us to resolve them in bulk instead of /// resolving each reference at a time. See the code in /// ResolveConstantForwardRefs for more information about this. /// /// The key of this vector is the placeholder constant, the value is the slot /// number that holds the resolved value. using ResolveConstantsTy = std::vector>; ResolveConstantsTy ResolveConstants; LLVMContext &Context; /// Maximum number of valid references. Forward references exceeding the /// maximum must be invalid. unsigned RefsUpperBound; public: BitcodeReaderValueList(LLVMContext &C, size_t RefsUpperBound) : Context(C), RefsUpperBound(std::min((size_t)std::numeric_limits::max(), RefsUpperBound)) {} ~BitcodeReaderValueList() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); } // vector compatibility methods unsigned size() const { return ValuePtrs.size(); } void resize(unsigned N) { ValuePtrs.resize(N); FullTypes.resize(N); } void push_back(Value *V, Type *Ty) { ValuePtrs.emplace_back(V); FullTypes.emplace_back(Ty); } void clear() { IGC_ASSERT(ResolveConstants.empty() && "Constants not resolved?"); ValuePtrs.clear(); FullTypes.clear(); } Value *operator[](unsigned i) const { IGC_ASSERT(i < ValuePtrs.size()); return ValuePtrs[i]; } Value *back() const { return ValuePtrs.back(); } void pop_back() { ValuePtrs.pop_back(); FullTypes.pop_back(); } bool empty() const { return ValuePtrs.empty(); } void shrinkTo(unsigned N) { IGC_ASSERT(N <= size() && "Invalid shrinkTo request!"); ValuePtrs.resize(N); FullTypes.resize(N); } Constant *getConstantFwdRef(unsigned Idx, Type *Ty); Value *getValueFwdRef(unsigned Idx, Type *Ty, Type **FullTy = nullptr); void assignValue(Value *V, unsigned Idx, Type *FullTy); /// Once all constants are read, this method bulk resolves any forward /// references. void resolveConstantForwardRefs(); }; } // end namespace llvm #endif // LLVM_LIB_BITCODE_READER_VALUELIST_H intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/000077500000000000000000000000001363533017100223305ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/CMakeLists.txt000066400000000000000000000045451363533017100251000ustar00rootroot00000000000000#===================== begin_copyright_notice ================================== #Copyright (c) 2017 Intel Corporation #Permission is hereby granted, free of charge, to any person obtaining a #copy of this software and associated documentation files (the #"Software"), to deal in the Software without restriction, including #without limitation the rights to use, copy, modify, merge, publish, #distribute, sublicense, and/or sell copies of the Software, and to #permit persons to whom the Software is furnished to do so, subject to #the following conditions: #The above copyright notice and this permission notice shall be included #in all copies or substantial portions of the Software. #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 AND NONINFRINGEMENT. #IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY #CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, #TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE #SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #======================= end_copyright_notice ================================== CMAKE_MINIMUM_REQUIRED( VERSION 3.1 ) PROJECT( CIF ) SET(gPtrSize 32) IF(CMAKE_SIZEOF_VOID_P EQUAL 8) set(gPtrSize 64) ENDIF() SET(ThirdPartyDir "third_party") SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) SET(CMAKE_CXX_STANDARD 17) SET(CMAKE_CXX_STANDARD_REQUIRED ON) IF(NOT MSVC) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=1024") ENDIF(NOT MSVC) INCLUDE_DIRECTORIES( "." ) INCLUDE_DIRECTORIES( "${ThirdPartyDir}/.." ) ADD_SUBDIRECTORY( cif ) MESSAGE( "Gathered CIF headers : ${CIF_HEADERS}" ) MESSAGE( "Gathered CIF headers : ${CIF_SOURCE}" ) MACRO(ADD_RUN_GTEST_TARGET TARGET_NAME CMD_NAME DEPENDENCIES) SET(ALL_DEPENDENCIES "${CMD_NAME}" "${DEPENDENCIES}") ADD_CUSTOM_TARGET(${TARGET_NAME} ALL DEPENDS ${ALL_DEPENDENCIES}) ADD_CUSTOM_COMMAND(TARGET ${TARGET_NAME} POST_BUILD WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT Running ${TARGET_NAME} tests COMMAND ${CMD_NAME} --gtest_repeat=1 --gtest_output=xml:test_out/test_details_18_1_3_8.xml ) ENDMACRO(ADD_RUN_GTEST_TARGET) ADD_SUBDIRECTORY( cif_tests ) intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/000077500000000000000000000000001363533017100230715ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/CMakeLists.txt000066400000000000000000000117261363533017100256400ustar00rootroot00000000000000#===================== begin_copyright_notice ================================== #Copyright (c) 2017 Intel Corporation #Permission is hereby granted, free of charge, to any person obtaining a #copy of this software and associated documentation files (the #"Software"), to deal in the Software without restriction, including #without limitation the rights to use, copy, modify, merge, publish, #distribute, sublicense, and/or sell copies of the Software, and to #permit persons to whom the Software is furnished to do so, subject to #the following conditions: #The above copyright notice and this permission notice shall be included #in all copies or substantial portions of the Software. #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 AND NONINFRINGEMENT. #IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY #CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, #TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE #SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #======================= end_copyright_notice ================================== FILE(GLOB_RECURSE CIF_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/.." "*.h") if(MSVC OR MINGW) SET(OS "win") else() SET(OS "lin") endif(MSVC OR MINGW) MACRO(MAKE_ABSOLUTE_PATHS ROOT_DIR RELATIVE_PATHS_LIST DST_ABSOLUTE_PATHS_LIST) SET(RET_LIST "") FOREACH(IT ${RELATIVE_PATHS_LIST}) SET(ABS_PATH ${ROOT_DIR}/${IT}) SET(RET_LIST "${RET_LIST};${ABS_PATH}") ENDFOREACH() SET(${DST_ABSOLUTE_PATHS_LIST} ${RET_LIST}) ENDMACRO(MAKE_ABSOLUTE_PATHS) MACRO(SET_CIF_FILTERS_SINGLE FILES_RELATIVE BASE_DIR FILTER_BASE) SET(ROOT_PATH "${BASE_DIR}cif/") GET_FILENAME_COMPONENT(ROOT_PATH_ABSOLUTE "${ROOT_PATH}" ABSOLUTE) FOREACH(IT ${FILES_RELATIVE}) GET_FILENAME_COMPONENT(PATH_WITHOUT_FILENAME ${IT} DIRECTORY) GET_FILENAME_COMPONENT(PATH_WITHOUT_FILENAME_ABSOLUTE "${PATH_WITHOUT_FILENAME}" ABSOLUTE) STRING(REPLACE "${ROOT_PATH_ABSOLUTE}" "" PARTIAL_PATH ${PATH_WITHOUT_FILENAME_ABSOLUTE}) STRING(REPLACE "/" "\\" FILTER ${PARTIAL_PATH}) SET(FILTER "${FILTER_BASE}${FILTER}") SOURCE_GROUP("${FILTER}" FILES "${IT}") ENDFOREACH(IT) ENDMACRO(SET_CIF_FILTERS_SINGLE) MACRO(SET_CIF_FILTERS SRC_CIF_SOURCES_RELATIVE SRC_CIF_HEADERS_RELATIVE BASE_DIR) SET_CIF_FILTERS_SINGLE("${SRC_CIF_SOURCES_RELATIVE}" "${BASE_DIR}" "cif\\\\sources\\\\") SET_CIF_FILTERS_SINGLE("${SRC_CIF_HEADERS_RELATIVE}" "${BASE_DIR}" "cif\\\\headers\\\\") ENDMACRO(SET_CIF_FILTERS) MACRO(CONCAT_LIST DST_LIST SRC_LIST SRC_PREFIX) SET(RET_LIST "") FOREACH(IT ${SRC_LIST}) SET(RET_LIST "${RET_LIST};${SRC_PREFIX}${IT}") ENDFOREACH(IT) SET(${DST_LIST} ${RET_LIST}) ENDMACRO(CONCAT_LIST) MACRO(GET_CIF_FILES_RELATIVE DST_CIF_SOURCES_EXPORT DST_CIF_SOURCES_IMPORT DST_CIF_HEADERS BASE_DIR) CONCAT_LIST(RET_CIF_SOURCES_EXPORT "${CIF_SOURCES_EXPORT}" "${BASE_DIR}") CONCAT_LIST(RET_CIF_SOURCES_IMPORT "${CIF_SOURCES_IMPORT}" "${BASE_DIR}") CONCAT_LIST(RET_CIF_HEADERS "${CIF_HEADERS}" "${BASE_DIR}") SET(${DST_CIF_SOURCES_EXPORT} ${RET_CIF_SOURCES_EXPORT}) SET(${DST_CIF_SOURCES_IMPORT} ${RET_CIF_SOURCES_IMPORT}) SET(${DST_CIF_HEADERS} ${RET_CIF_HEADERS}) ENDMACRO(GET_CIF_FILES_RELATIVE) SET(CIF_BUILTINS_SOURCES cif/builtins/memory/buffer/impl/buffer_impl.cpp ) SET(CIF_SOURCES_EXPORT "${CIF_BUILTINS_SOURCES}" cif/builtins/builtins_registry.cpp cif/export/cif_main.cpp cif/export/registry.cpp cif/helpers/error.cpp ) SET(CIF_SOURCES_IMPORT cif/import/cif_main.cpp cif/os/${OS}/${OS}_library_handle.cpp cif/helpers/error.cpp ) SET(CIF_SOURCES "${CIF_SOURCES_IMPORT};${CIF_SOURCES_EXPORT}") MAKE_ABSOLUTE_PATHS("${CMAKE_CURRENT_SOURCE_DIR}/.." "${CIF_SOURCES_EXPORT}" CIF_SOURCES_EXPORT_ABSOLUTE_PATH) MAKE_ABSOLUTE_PATHS("${CMAKE_CURRENT_SOURCE_DIR}/.." "${CIF_SOURCES_IMPORT}" CIF_SOURCES_IMPORT_ABSOLUTE_PATH) SET(CIF_SOURCES_ABSOLUTE_PATH "${CIF_SOURCES_EXPORT_ABSOLUTE_PATH};${CIF_SOURCES_IMPORT_ABSOLUTE_PATH}") MAKE_ABSOLUTE_PATHS("${CMAKE_CURRENT_SOURCE_DIR}/.." "${CIF_HEADERS}" CIF_HEADERS_ABSOLUTE_PATH) # Export these to parent CMake SET(CIF_HEADERS ${CIF_HEADERS} PARENT_SCOPE) SET(CIF_SOURCES_EXPORT ${CIF_SOURCES_EXPORT} PARENT_SCOPE) SET(CIF_SOURCES_IMPORT ${CIF_SOURCES_IMPORT} PARENT_SCOPE) SET(CIF_SOURCES ${CIF_SOURCES} PARENT_SCOPE) SET(CIF_SOURCES_EXPORT_ABSOLUTE_PATH ${CIF_SOURCES_EXPORT_ABSOLUTE_PATH} PARENT_SCOPE) SET(CIF_SOURCES_IMPORT_ABSOLUTE_PATH ${CIF_SOURCES_IMPORT_ABSOLUTE_PATH} PARENT_SCOPE) SET(CIF_SOURCES_ABSOLUTE_PATH ${CIF_SOURCES_ABSOLUTE_PATH} PARENT_SCOPE) SET(CIF_HEADERS_ABSOLUTE_PATH ${CIF_HEADERS_ABSOLUTE_PATH} PARENT_SCOPE) SET(CIF_FOUND TRUE PARENT_SCOPE) SET(CIF_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." PARENT_SCOPE) intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/000077500000000000000000000000001363533017100247225ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/builtins_registry.cpp000066400000000000000000000045131363533017100312120ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "cif/builtins/builtins_registry.h" #include "cif/export/cif_main_impl.h" #include "cif/builtins/memory/buffer/impl/buffer_impl.h" namespace CIF { namespace Builtins { // List of all supported builtins using AllBuiltinsListT = InterfacesList; bool IsBuiltin(InterfaceId_t intId){ return AllBuiltinsListT::ContainsInterface(intId); } ICIF *Create(InterfaceId_t entryPointInterface, Version_t version, ICIF *parentInterface){ return AllBuiltinsListT::template forwardToOne(entryPointInterface, nullptr, version, version, parentInterface); } bool GetSupportedVersions(InterfaceId_t entryPointInterface, Version_t &verMin, Version_t &verMax){ return AllBuiltinsListT::template forwardToOne(entryPointInterface, false, verMin, verMax); } InterfaceId_t FindIncompatible(InterfaceId_t entryPointInterface, CIF::CompatibilityDataHandle handle){ return AllBuiltinsListT::template forwardToOne(entryPointInterface, entryPointInterface, handle); } } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/builtins_registry.h000066400000000000000000000032651363533017100306620ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cif/common/cif.h" #include "cif/common/compatibility.h" #include "cif/common/id.h" namespace CIF { namespace Builtins { bool IsBuiltin(InterfaceId_t intId); ICIF *Create(InterfaceId_t entryPointInterface, Version_t version, ICIF *parentInterface); bool GetSupportedVersions(InterfaceId_t entryPointInterface, Version_t &verMin, Version_t &verMax); InterfaceId_t FindIncompatible(InterfaceId_t entryPointInterface, CIF::CompatibilityDataHandle handle); } } intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/memory/000077500000000000000000000000001363533017100262325ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/memory/buffer/000077500000000000000000000000001363533017100275035ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/memory/buffer/buffer.h000066400000000000000000000166241363533017100311360ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #include "cif/common/id.h" #include "cif/common/cif.h" #include "cif/common/cif_main.h" #include "cif/macros/enable.h" namespace CIF { namespace Builtins { /// Custom allocator function using AllocatorT = void *(CIF_CALLING_CONV *)(size_t size); /// Custom allocator function using ReallocatorT = void *(CIF_CALLING_CONV *)(void *oldMemory, size_t oldSize, size_t newSize); /// Custom deallocator function using DeallocatorT = void (CIF_CALLING_CONV *)(void *memory); /// Builtin interface that can be used as generic buffer CIF_DECLARE_COMMON_INTERFACE(Buffer, "CIF_BUFFER"); /// v #1 CIF_DEFINE_INTERFACE_VER(Buffer, 1){ CIF_INHERIT_CONSTRUCTOR(); /// Get address to underlying buffer with ElementT as pointer element type template ElementT *GetMemoryWriteable(){ return reinterpret_cast(GetMemoryRawWriteable()); } /// Get address to underlying const buffer with ElementT as pointer element type template const ElementT *GetMemory() const{ return reinterpret_cast(GetMemoryRaw()); } /// Get size in units of ElementT (ElementT == void version) template const typename std::enable_if::value, size_t>::type GetSize() const{ return GetSizeRaw(); } /// Get size in units of ElementT (ElementT != void version) template const typename std::enable_if::value, size_t>::type GetSize() const{ return GetSizeRaw() / sizeof(ElementT); } /// Copies given element to the end of the buffer /// Note : If (packed == false), then this function will automatically align current underlying buffer /// pointer to alignof(ElementT) template bool PushBackRawCopy(const ElementT &newEl, bool packed = true){ static_assert(std::is_pod::value, "Supporting only POD types"); if(packed == false){ size_t alignment = alignof(ElementT); bool success = AlignUp(static_cast(alignment)); if(success == false){ return false; } } return PushBackRawBytes(&newEl, sizeof(ElementT)); } /// Sets custom allocator and deallocator functions to be used by this buffer interface /// Note : will reallocate using new allocators only when additional space will be needed /// Note : reallocator is optional and can be nullptr virtual void SetAllocator(AllocatorT allocator, DeallocatorT deallocator, ReallocatorT reallocator); /// Sets underlying buffer storage and its deallocator /// Note : will destroy current underlying buffer (if any) /// Note : if size of given memory becomes too small, will fallback to allocating new memory virtual void SetUnderlyingStorage(void *memory, size_t size, DeallocatorT deallocator); /// Sets underlying constant buffer storage and its deallocator /// Note : will destroy current underlying buffer (if any) /// Note : will allocate new memory if this const memory will be accessed in non-const manners /// Note : since given pointer is treated as const, memory pointed ty by it will never be freed /// by this buffer instance virtual void SetUnderlyingStorage(const void *memory, size_t size); /// Detaches and returns current allocation leaving this buffer's underlying buffer empty virtual void *DetachAllocation(); /// Returns const raw access to underlying buffer virtual const void *GetMemoryRaw() const; /// Returns writeable access to underlyng buffer /// Note : for constant buffer this will cause reallocation (copy!) to writeable memory virtual void *GetMemoryRawWriteable(); /// Returns size in bytes of underlying buffer virtual size_t GetSizeRaw() const; /// Returns capacity in bytes of underlying buffer virtual size_t GetCapacityRaw() const; /// Resizes (may reallocate) underlying buffer's size virtual bool Resize(size_t newSize); /// Resizes (may reallocate) the underlying buffer's capacity virtual bool Reserve(size_t newCapacity); /// Sets the size to 0 virtual void Clear(); /// Sets the size to 0 and deallocates underlying buffer virtual void Deallocate(); /// Aligns up current size to meet required alignment virtual bool AlignUp(uint32_t alignment); /// Pushes new raw element to buffer virtual bool PushBackRawBytes(const void *newData, size_t size); /// Can be true if SetUnderlyingStorage(const void *, size_t) was used, please refer to SetUnderlyingStorage virtual bool IsConst() const; }; CIF_GENERATE_VERSIONS_LIST(Buffer); CIF_MARK_LATEST_VERSION(BufferLatest, Buffer); using BufferSimple = Buffer<1>; /// tag the most common version template CIF::RAII::UPtr_t CreateConstBuffer(CIF::CIFMain *provider, const void *data, size_t size){ if(provider == nullptr){ return CIF::RAII::UPtr(nullptr); } auto buff = provider->CreateBuiltin(); if(buff == nullptr){ return CIF::RAII::UPtr(nullptr); } if((data != nullptr) && (size != 0)){ buff->SetUnderlyingStorage(data, size); } return buff; } template CIF::RAII::UPtr_t CreateWriteableBuffer(CIF::CIFMain *provider, const void *initialData, size_t initialSize){ auto *buff = CreateConstBuffer(provider, initialData, initialSize); if(buff == nullptr){ return CIF::RAII::UPtr(nullptr); } auto writeableMem = buff->GetMemoryRawWriteable(); if(writeableMem == nullptr){ // failed to allocate new memory in writeable memory return CIF::RAII::UPtr(nullptr); } return buff; } template CIF::RAII::UPtr_t CreateBufferFromPtr(CIF::CIFMain *provider, void *ptr, size_t size, DeallocatorT ptrDeallocator){ auto *buff = CreateConstBuffer(provider, nullptr, 0); if(buff == nullptr){ return CIF::RAII::UPtr(nullptr); } buff->SetUnderlyingStorage(ptr, size, ptrDeallocator); return buff; } } } #include "cif/macros/disable.h" intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/memory/buffer/impl/000077500000000000000000000000001363533017100304445ustar00rootroot00000000000000buffer_impl.cpp000066400000000000000000000064341363533017100333720ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/memory/buffer/impl/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #include "cif/builtins/memory/buffer/buffer.h" #include "cif/builtins/memory/buffer/impl/buffer_impl.h" #include "cif/macros/enable.h" namespace CIF{ namespace Builtins{ void CIF_GET_INTERFACE_CLASS(Buffer, 1)::SetAllocator(AllocatorT allocator, DeallocatorT deallocator, ReallocatorT reallocator){ CIF_GET_PIMPL()->SetAllocator(allocator, deallocator, reallocator); } void CIF_GET_INTERFACE_CLASS(Buffer, 1)::SetUnderlyingStorage(void *memory, size_t size, DeallocatorT deallocator){ CIF_GET_PIMPL()->SetUnderlyingStorage(memory, size, deallocator); } void CIF_GET_INTERFACE_CLASS(Buffer, 1)::SetUnderlyingStorage(const void *memory, size_t size){ CIF_GET_PIMPL()->SetUnderlyingStorage(memory, size); } void *CIF_GET_INTERFACE_CLASS(Buffer, 1)::DetachAllocation(){ return CIF_GET_PIMPL()->DetachAllocation(); } const void *CIF_GET_INTERFACE_CLASS(Buffer, 1)::GetMemoryRaw() const{ return CIF_GET_PIMPL()->GetMemoryRaw(); } void *CIF_GET_INTERFACE_CLASS(Buffer, 1)::GetMemoryRawWriteable(){ return CIF_GET_PIMPL()->GetMemoryRawWriteable(); } size_t CIF_GET_INTERFACE_CLASS(Buffer, 1)::GetSizeRaw() const{ return CIF_GET_PIMPL()->GetSizeRaw(); } size_t CIF_GET_INTERFACE_CLASS(Buffer, 1)::GetCapacityRaw() const{ return CIF_GET_PIMPL()->GetCapacityRaw(); } bool CIF_GET_INTERFACE_CLASS(Buffer, 1)::Resize(size_t newSize){ return CIF_GET_PIMPL()->Resize(newSize); } bool CIF_GET_INTERFACE_CLASS(Buffer, 1)::Reserve(size_t newCapacity){ return CIF_GET_PIMPL()->Reserve(newCapacity); } void CIF_GET_INTERFACE_CLASS(Buffer, 1)::Clear(){ CIF_GET_PIMPL()->Clear(); } void CIF_GET_INTERFACE_CLASS(Buffer, 1)::Deallocate(){ CIF_GET_PIMPL()->Deallocate(); } bool CIF_GET_INTERFACE_CLASS(Buffer, 1)::AlignUp(uint32_t alignment){ return CIF_GET_PIMPL()->AlignUp(alignment); } bool CIF_GET_INTERFACE_CLASS(Buffer, 1)::PushBackRawBytes(const void *newData, size_t size){ return CIF_GET_PIMPL()->PushBackRawBytes(newData, size); } bool CIF_GET_INTERFACE_CLASS(Buffer, 1)::IsConst()const{ return CIF_GET_PIMPL()->IsConst(); } } } #include "cif/macros/disable.h" buffer_impl.h000066400000000000000000000236011363533017100330320ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/builtins/memory/buffer/impl/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include "cif/builtins/memory/buffer/buffer.h" #include "cif/export/pimpl_base.h" #include "cif/macros/enable.h" #include "cif/helpers/memory.h" namespace CIF { namespace Builtins { CIF_DECLARE_INTERFACE_PIMPL(Buffer) : CIF::PimplBase { CIF_PIMPL_DECLARE_CONSTRUCTOR(Version_t version, CIF::ICIF *parentInterface) { } CIF_PIMPL_DECLARE_CONSTRUCTOR(Version_t version) { } CIF_PIMPL_DECLARE_CONSTRUCTOR() { } CIF_PIMPL_DECLARE_DESTRUCTOR(){ Deallocate(); } /// Copies given element to the end of the buffer /// Note : If (packed == false), then this function will automatically align current underlying buffer /// pointer to alignof(ElementT) template bool PushBackRawCopy(const ElementT &newEl, bool packed = true){ static_assert(std::is_pod::value, "Supporting only POD types"); if(packed == false){ size_t alignment = alignof(ElementT); bool success = AlignUp(alignment); if(success == false){ return false; } } return PushBackRawBytes(&newEl, sizeof(ElementT)); } /// Sets custom allocator and deallocator functions to be used by this buffer interface /// Note : will reallocate using new allocators only when additional space will be needed /// Note : reallocator is optional and can be nullptr void SetAllocator(AllocatorT allocator, DeallocatorT deallocator, ReallocatorT reallocator){ if(allocator == nullptr){ allocator = EmptyAllocator; } if((this->memory) && (this->tempDeallocator == nullptr)){ this->tempDeallocator = this->deallocator; } this->allocator = allocator; this->deallocator = deallocator; this->reallocator = reallocator; } /// Sets underlying buffer storage and its deallocator /// Note : will destroy current underlying buffer (if any) void SetUnderlyingStorage(void *memory, size_t size, DeallocatorT deallocator){ Deallocate(); this->memory = memory; this->size = size; this->capacity = size; this->tempDeallocator = deallocator; } /// Sets underlying constant buffer storage and its deallocator /// Note : will destroy current underlying buffer (if any) /// Note : will allocate new memory if this const memory will be accessed in non-const manners void SetUnderlyingStorage(const void *memory, size_t size){ Deallocate(); // casting-away constness, but marking as const this->memory = const_cast(memory); this->isConst = true; this->size = size; this->capacity = size; this->tempDeallocator = nullptr; } /// Detaches and returns current allocation leaving this buffer's underlying buffer empty void *DetachAllocation(){ void *mem = memory; this->memory = nullptr; this->size = 0; this->capacity = 0; this->isConst = false; this->tempDeallocator = nullptr; return mem; } /// Returns const raw access to underlying buffer const void *GetMemoryRaw() const{ return memory; } /// Returns writeable access to underlyng buffer /// Note : for constant buffer this will cause reallocation (copy!) to writeable memory void *GetMemoryRawWriteable(){ if(this->isConst){ if(false == Reallocate(this->size, this->capacity)){ return nullptr; } } return memory; } /// Returns size in bytes of underlying buffer size_t GetSizeRaw() const{ return size; } /// Returns capacity in bytes of underlying buffer size_t GetCapacityRaw() const{ return capacity; } /// Resizes (may reallocate) underlying buffer's size bool Resize(size_t newSize) { return this->Reallocate(newSize, std::max(this->capacity, newSize)); } /// Resizes (may reallocate) the underlying buffer's capacity bool Reserve(size_t newCapacity){ return this->Reallocate(this->size, newCapacity); } /// Sets the size to 0 void Clear(){ this->size = 0; } /// Sets the size to 0 and deallocates underlying buffer void Deallocate(){ if(isConst){ this->memory = nullptr; this->size = 0; this->capacity = 0; this->isConst = false; this->tempDeallocator = nullptr; }else if(tempDeallocator){ tempDeallocator(this->memory); this->memory = nullptr; this->size = 0; this->capacity = 0; this->tempDeallocator = nullptr; }else{ if(deallocator != nullptr){ deallocator(this->memory); } this->memory = nullptr; this->size = 0; this->capacity = 0; } } /// Aligns up current size to meet required alignment bool AlignUp(uint32_t alignment){ size_t misalligned = alignment - (this->size % alignment); size_t newSize = this->size + misalligned; return Reallocate(newSize, newSize); } /// Pushes new raw element to buffer bool PushBackRawBytes(const void *newData, size_t size){ if(size == 0){ // nothing to do return true; } size_t oldSize = this->size; if(false == Reallocate(this->size + size, this->size + size)){ return false; } CIF::SafeCopy(CIF::OffsetedPtr(GetMemoryRawWriteable(), oldSize), this->capacity - oldSize, newData, size); return true; } /// Can be true if SetUnderlyingStorage(const void *, size_t) was used, please refer to SetUnderlyingStorage bool IsConst() const{ return isConst; } protected: static void * CIF_CALLING_CONV EmptyAllocator(size_t size){ return nullptr; } static void * CIF_CALLING_CONV DefaultAllocator(size_t size){ return new(std::nothrow) char[size]; } static void CIF_CALLING_CONV DefaultDeallocator(void * memory){ if(memory != nullptr){ delete []reinterpret_cast(memory); } } bool Reallocate(size_t newSize, size_t newCapacity){ if(isConst){ void * newMem = this->allocator(newCapacity); if(newMem == nullptr){ return false; } size_t bytesToCopy = std::min(newSize, this->size); CIF::SafeCopy(newMem, newCapacity, this->memory, bytesToCopy); this->memory = newMem; this->isConst = false; this->tempDeallocator = nullptr; this->capacity = newCapacity; this->size = newSize; return true; } if(tempDeallocator != nullptr){ if(newCapacity <= this->capacity){ this->size = newSize; return true; } void * newMem = this->allocator(newCapacity); if(newMem == nullptr){ return false; } size_t bytesToCopy = std::min(newSize, this->size); CIF::SafeCopy(newMem, newCapacity, this->memory, bytesToCopy); void *oldMemory = this->memory; this->memory = newMem; this->capacity = newCapacity; this->size = newSize; this->tempDeallocator(oldMemory); this->tempDeallocator = nullptr; return true; } if(newCapacity <= this->capacity){ this->size = newSize; return true; } if(reallocator != nullptr){ void *newMem = reallocator(this->memory, this->capacity, newCapacity); if(newMem == nullptr){ return false; } this->memory = newMem; this->capacity = newCapacity; this->size = newSize; return true; } void *newMem = allocator(newCapacity); if(newMem == nullptr){ return false; } size_t bytesToCopy = std::min(newSize, this->size); CIF::SafeCopy(newMem, newCapacity, this->memory, bytesToCopy); if(deallocator != nullptr){ deallocator(this->memory); } this->memory = newMem; this->capacity = newCapacity; this->size = newSize; return true; } void *memory = nullptr; size_t size = 0; size_t capacity = 0; bool isConst = false; DeallocatorT tempDeallocator = nullptr; AllocatorT allocator = DefaultAllocator; DeallocatorT deallocator = DefaultDeallocator; ReallocatorT reallocator = nullptr; }; CIF_DEFINE_INTERFACE_TO_PIMPL_FORWARDING_CTOR_DTOR(Buffer); } } #include "cif/macros/disable.h" intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/common/000077500000000000000000000000001363533017100243615ustar00rootroot00000000000000intel-graphics-compiler-igc-1.0.3627/IGC/AdaptorOCL/cif/cif/common/cif.h000066400000000000000000000411571363533017100253030ustar00rootroot00000000000000/*===================== begin_copyright_notice ================================== Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================= end_copyright_notice ==================================*/ #pragma once #include #include #include #include #include #include #include #include "cif/common/id.h" namespace CIF { constexpr Version_t CifFrameworkVersion = 2; namespace RAII { template struct ReleaseHelper { void operator() (T *handle) const { assert(handle != nullptr); handle->Release(); } }; template using UPtr_t = std::unique_ptr>; template static UPtr_t UPtr(T *handle) { return UPtr_t(handle); } template UPtr_t RetainAndPack(SrcType * ptr){ if(ptr == nullptr){ return UPtr(nullptr); } ptr->Retain(); return UPtr(static_cast(ptr)); } template UPtr_t Pack(SrcType * ptr){ if(ptr == nullptr){ return UPtr(nullptr); } return UPtr(static_cast(ptr)); } } // generic interface for all components struct ICIF { ICIF(const ICIF &) = delete; ICIF &operator=(const ICIF &) = delete; ICIF(ICIF &&) = delete; ICIF *operator=(ICIF &&) = delete; virtual void Release() = 0; virtual void Retain() = 0; virtual uint32_t GetRefCount() const = 0; virtual Version_t GetEnabledVersion() const = 0; virtual Version_t GetUnderlyingVersion() const { return GetEnabledVersion(); // by default : redirect to enabled version } virtual bool GetSupportedVersions(InterfaceId_t intId, Version_t &verMin, Version_t &verMax) const { return false; // by default : no sub-interface are supported } // get specific version of interface template RAII::UPtr_t CreateInterface() { static_assert((version >= InterfaceT::GetBackwardsCompatibilityVersion()) && (version <= InterfaceT::GetVersion()), "Invalid version requested"); return RAII::UPtr(reinterpret_cast( CreateInterfaceImpl(InterfaceT::GetInterfaceId(), version))); } // get latest version of interface that matches interface class template RAII::UPtr_t CreateInterface() { uint64_t minVerSupported = 0; uint64_t maxVerSupported = 0; if (false == GetSupportedVersions(InterfaceT::GetInterfaceId(), minVerSupported, maxVerSupported)) { // interface not supported return RAII::UPtr(nullptr); } if ((InterfaceT::GetVersion() < minVerSupported) || (InterfaceT::GetVersion() > maxVerSupported)) { // interface version not supported return RAII::UPtr(nullptr); } // get latest compatible uint64_t chosenVersion = std::min(maxVerSupported, InterfaceT::GetVersion()); return RAII::UPtr(reinterpret_cast( CreateInterfaceImpl(InterfaceT::GetInterfaceId(), chosenVersion))); } protected: ICIF() = default; virtual ~ICIF() = default; virtual ICIF *CreateInterfaceImpl(InterfaceId_t intId, Version_t version) { return nullptr; // by default : no sub-interface are supported } }; template struct NamedCIF : public BaseClass { static constexpr InterfaceId_t GetInterfaceId() { return id; }; }; template