text: /*========================== begin_copyright_notice ============================
  
  Copyright (C) 2017-2021 Intel Corporation
  
  SPDX-License-Identifier: MIT
  
  ============================= end_copyright_notice ===========================*/
  
  #include "SpirMetaDataApi.h"
  #include "Probe/Assertion.h"
  
  namespace IGC {
      namespace SPIRMD
      {
          static bool isNamedNode(const llvm::Metadata*, const char*);
  
          ///
          // Ctor - loads the VectorTypeHintMetaData from the given metadata node
          //
          VectorTypeHintMetaData::VectorTypeHintMetaData(const llvm::MDNode* pNode, bool hasId) :
              _Mybase(pNode, hasId),
              m_VecType(getVecTypeNode(pNode)),
              m_Sign(getSignNode(pNode)),
              m_pNode(pNode)
          {}
  
          ///
          // Default Ctor - creates the empty, not named VectorTypeHintMetaData object
          //
          VectorTypeHintMetaData::VectorTypeHintMetaData() :
              m_pNode(NULL)
          {}
  
          ///
          // Ctor - creates the empty, named VectorTypeHintMetaData object
          //
          VectorTypeHintMetaData::VectorTypeHintMetaData(const char* name) :
              _Mybase(name),
              m_pNode(NULL)
          {}
  
          bool VectorTypeHintMetaData::hasValue() const
          {
              if (m_VecType.hasValue())
              {
                  return true;
              }
  
  
              if (m_Sign.hasValue())
              {
                  return true;
              }
              return NULL != m_pNode || dirty();
          }
  
          ///
          // Returns true if any of the VectorTypeHintMetaData`s members has changed
          bool VectorTypeHintMetaData::dirty() const
          {
              if (m_VecType.dirty())
              {
                  return true;
              }
              if (m_Sign.dirty())
              {
                  return true;
              }
              return false;
          }
  
          ///
          // Discards the changes done to the VectorTypeHintMetaData instance
          void VectorTypeHintMetaData::discardChanges()
          {
              m_VecType.discardChanges();
              m_Sign.discardChanges();
          }
  
          ///
          // Generates the new MDNode hierarchy for the given structure
          llvm::Metadata* VectorTypeHintMetaData::generateNode(llvm::LLVMContext& context) const
          {
              llvm::SmallVector<llvm::Metadata*, 5> args;
  
              llvm::Metadata* pIDNode = _Mybase::generateNode(context);
              if (NULL != pIDNode)
              {
                  args.push_back(pIDNode);
              }
  
              args.push_back(m_VecType.generateNode(context));
              args.push_back(m_Sign.generateNode(context));
  
              return llvm::MDNode::get(context, args);
          }
  
          ///
          // Saves the structure changes to the given MDNode
          void VectorTypeHintMetaData::save(llvm::LLVMContext& context, llvm::MDNode* pNode) const
          {
              IGC_ASSERT_MESSAGE(nullptr != pNode, "The target node should be valid pointer");
  
              // we assume that underlying metadata node has not changed under our foot
              if (pNode == m_pNode && !dirty())
              {
                  return;
              }
  #if 0
              // check that we could save the new information to the given node without regenerating it
              if (!compatibleWith(pNode))
              {
                  pNode->replaceAllUsesWith(generateNode(context));
                  return;
              }
  #endif
  
              m_VecType.save(context, llvm::cast<llvm::MDNode>(getVecTypeNode(pNode)));
              m_Sign.save(context, llvm::cast<llvm::MDNode>(getSignNode(pNode)));
          }
  
          llvm::Metadata* VectorTypeHintMetaData::getVecTypeNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(0 + offset).get();
          }
  
          llvm::Metadata* VectorTypeHintMetaData::getSignNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(1 + offset).get();
          }
  
          ///
          // Ctor - loads the VersionMetaData from the given metadata node
          //
          VersionMetaData::VersionMetaData(const llvm::MDNode* pNode, bool hasId) :
              _Mybase(pNode, hasId),
              m_Major(getMajorNode(pNode)),
              m_Minor(getMinorNode(pNode)),
              m_pNode(pNode)
          {}
  
          ///
          // Default Ctor - creates the empty, not named VersionMetaData object
          //
          VersionMetaData::VersionMetaData() :
              m_pNode(NULL)
          {}
  
          ///
          // Ctor - creates the empty, named VersionMetaData object
          //
          VersionMetaData::VersionMetaData(const char* name) :
              _Mybase(name),
              m_pNode(NULL)
          {}
  
          bool VersionMetaData::hasValue() const
          {
              if (m_Major.hasValue())
              {
                  return true;
              }
  
  
              if (m_Minor.hasValue())
              {
                  return true;
              }
              return NULL != m_pNode || dirty();
          }
  
          ///
          // Returns true if any of the VersionMetaData`s members has changed
          bool VersionMetaData::dirty() const
          {
              if (m_Major.dirty())
              {
                  return true;
              }
              if (m_Minor.dirty())
              {
                  return true;
              }
              return false;
          }
  
          ///
          // Discards the changes done to the VersionMetaData instance
          void VersionMetaData::discardChanges()
          {
              m_Major.discardChanges();
              m_Minor.discardChanges();
          }
  
          ///
          // Generates the new MDNode hierarchy for the given structure
          llvm::Metadata* VersionMetaData::generateNode(llvm::LLVMContext& context) const
          {
              llvm::SmallVector<llvm::Metadata*, 5> args;
  
              llvm::Metadata* pIDNode = _Mybase::generateNode(context);
              if (NULL != pIDNode)
              {
                  args.push_back(pIDNode);
              }
  
              args.push_back(m_Major.generateNode(context));
              args.push_back(m_Minor.generateNode(context));
  
              return llvm::MDNode::get(context, args);
          }
  
          ///
          // Saves the structure changes to the given MDNode
          void VersionMetaData::save(llvm::LLVMContext& context, llvm::MDNode* pNode) const
          {
              IGC_ASSERT_MESSAGE(nullptr != pNode, "The target node should be valid pointer");
  
              // we assume that underlying metadata node has not changed under our foot
              if (pNode == m_pNode && !dirty())
              {
                  return;
              }
  #if 0
              // check that we could save the new information to the given node without regenerating it
              if (!compatibleWith(pNode))
              {
                  pNode->replaceAllUsesWith(generateNode(context));
                  return;
              }
  #endif
  
              m_Major.save(context, llvm::cast<llvm::MDNode>(getMajorNode(pNode)));
              m_Minor.save(context, llvm::cast<llvm::MDNode>(getMinorNode(pNode)));
          }
  
          llvm::Metadata* VersionMetaData::getMajorNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(0 + offset).get();
          }
  
          llvm::Metadata* VersionMetaData::getMinorNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(1 + offset).get();
          }
  
  
  
          ///
          // Ctor - loads the WorkGroupDimensionsMetaData from the given metadata node
          //
          WorkGroupDimensionsMetaData::WorkGroupDimensionsMetaData(const llvm::MDNode* pNode, bool hasId) :
              _Mybase(pNode, hasId),
              m_XDim(getXDimNode(pNode)),
              m_YDim(getYDimNode(pNode)),
              m_ZDim(getZDimNode(pNode)),
              m_pNode(pNode)
          {}
  
          ///
          // Default Ctor - creates the empty, not named WorkGroupDimensionsMetaData object
          //
          WorkGroupDimensionsMetaData::WorkGroupDimensionsMetaData() :
              m_pNode(NULL)
          {}
  
          ///
          // Ctor - creates the empty, named WorkGroupDimensionsMetaData object
          //
          WorkGroupDimensionsMetaData::WorkGroupDimensionsMetaData(const char* name) :
              _Mybase(name),
              m_pNode(NULL)
          {}
  
          bool WorkGroupDimensionsMetaData::hasValue() const
          {
              if (m_XDim.hasValue())
              {
                  return true;
              }
  
  
              if (m_YDim.hasValue())
              {
                  return true;
              }
  
  
              if (m_ZDim.hasValue())
              {
                  return true;
              }
              return NULL != m_pNode || dirty();
          }
  
          ///
          // Returns true if any of the WorkGroupDimensionsMetaData`s members has changed
          bool WorkGroupDimensionsMetaData::dirty() const
          {
              if (m_XDim.dirty())
              {
                  return true;
              }
              if (m_YDim.dirty())
              {
                  return true;
              }
              if (m_ZDim.dirty())
              {
                  return true;
              }
              return false;
          }
  
          ///
          // Discards the changes done to the WorkGroupDimensionsMetaData instance
          void WorkGroupDimensionsMetaData::discardChanges()
          {
              m_XDim.discardChanges();
              m_YDim.discardChanges();
              m_ZDim.discardChanges();
          }
  
          ///
          // Generates the new MDNode hierarchy for the given structure
          llvm::Metadata* WorkGroupDimensionsMetaData::generateNode(llvm::LLVMContext& context) const
          {
              llvm::SmallVector<llvm::Metadata*, 5> args;
  
              llvm::Metadata* pIDNode = _Mybase::generateNode(context);
              if (NULL != pIDNode)
              {
                  args.push_back(pIDNode);
              }
  
              args.push_back(m_XDim.generateNode(context));
              args.push_back(m_YDim.generateNode(context));
              args.push_back(m_ZDim.generateNode(context));
  
              return llvm::MDNode::get(context, args);
          }
  
          ///
          // Saves the structure changes to the given MDNode
          void WorkGroupDimensionsMetaData::save(llvm::LLVMContext& context, llvm::MDNode* pNode) const
          {
              IGC_ASSERT_MESSAGE(nullptr != pNode, "The target node should be valid pointer");
  
              // we assume that underlying metadata node has not changed under our foot
              if (pNode == m_pNode && !dirty())
              {
                  return;
              }
  #if 0
              // check that we could save the new information to the given node without regenerating it
              if (!compatibleWith(pNode))
              {
                  pNode->replaceAllUsesWith(generateNode(context));
                  return;
              }
  #endif
  
              m_XDim.save(context, llvm::cast<llvm::MDNode>(getXDimNode(pNode)));
              m_YDim.save(context, llvm::cast<llvm::MDNode>(getYDimNode(pNode)));
              m_ZDim.save(context, llvm::cast<llvm::MDNode>(getZDimNode(pNode)));
          }
  
          llvm::Metadata* WorkGroupDimensionsMetaData::getXDimNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(0 + offset).get();
          }
  
          llvm::Metadata* WorkGroupDimensionsMetaData::getYDimNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(1 + offset).get();
          }
  
          llvm::Metadata* WorkGroupDimensionsMetaData::getZDimNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(2 + offset).get();
          }
  
  
  
          ///
          // Ctor - loads the SubGroupDimensionsMetaData from the given metadata node
          //
          SubGroupDimensionsMetaData::SubGroupDimensionsMetaData(const llvm::MDNode* pNode, bool hasId) :
              _Mybase(pNode, hasId),
              m_SIMD_Size(getSIMD_SizeNode(pNode)),
              m_pNode(pNode)
          {}
  
          ///
          // Default Ctor - creates the empty, not named SubGroupDimensionsMetaData object
          //
          SubGroupDimensionsMetaData::SubGroupDimensionsMetaData() :
              m_pNode(NULL)
          {}
  
          ///
          // Ctor - creates the empty, named SubGroupDimensionsMetaData object
          //
          SubGroupDimensionsMetaData::SubGroupDimensionsMetaData(const char* name) :
              _Mybase(name),
              m_pNode(NULL)
          {}
  
          bool SubGroupDimensionsMetaData::hasValue() const
          {
              if (m_SIMD_Size.hasValue())
              {
                  return true;
              }
              return NULL != m_pNode || dirty();
          }
  
          ///
          // Returns true if any of the SubGroupDimensionsMetaData`s members has changed
          bool SubGroupDimensionsMetaData::dirty() const
          {
              if (m_SIMD_Size.dirty())
              {
                  return true;
              }
              return false;
          }
  
          ///
          // Discards the changes done to the SubGroupDimensionsMetaData instance
          void SubGroupDimensionsMetaData::discardChanges()
          {
              m_SIMD_Size.discardChanges();
          }
  
          ///
          // Generates the new MDNode hierarchy for the given structure
          llvm::Metadata* SubGroupDimensionsMetaData::generateNode(llvm::LLVMContext& context) const
          {
              llvm::SmallVector<llvm::Metadata*, 5> args;
  
              llvm::Metadata* pIDNode = _Mybase::generateNode(context);
              if (NULL != pIDNode)
              {
                  args.push_back(pIDNode);
              }
  
              args.push_back(m_SIMD_Size.generateNode(context));
  
              return llvm::MDNode::get(context, args);
          }
  
          ///
          // Saves the structure changes to the given MDNode
          void SubGroupDimensionsMetaData::save(llvm::LLVMContext& context, llvm::MDNode* pNode) const
          {
              IGC_ASSERT_MESSAGE(nullptr != pNode, "The target node should be valid pointer");
  
              // we assume that underlying metadata node has not changed under our foot
              if (pNode == m_pNode && !dirty())
              {
                  return;
              }
  #if 0
              // check that we could save the new information to the given node without regenerating it
              if (!compatibleWith(pNode))
              {
                  pNode->replaceAllUsesWith(generateNode(context));
                  return;
              }
  #endif
  
              m_SIMD_Size.save(context, llvm::cast<llvm::MDNode>(getSIMD_SizeNode(pNode)));
          }
  
          llvm::Metadata* SubGroupDimensionsMetaData::getSIMD_SizeNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(0 + offset).get();
          }
  
  
          ///
          // Ctor - loads the WorkgroupWalkOrderMetaData from the given metadata node
          //
          WorkgroupWalkOrderMetaData::WorkgroupWalkOrderMetaData(const llvm::MDNode* pNode, bool hasId) :
              _Mybase(pNode, hasId),
              m_Dim0(getDim0Node(pNode)),
              m_Dim1(getDim1Node(pNode)),
              m_Dim2(getDim2Node(pNode)),
              m_pNode(pNode)
          {}
  
          ///
          // Default Ctor - creates the empty, not named SubGroupSizeMetaData object
          //
          WorkgroupWalkOrderMetaData::WorkgroupWalkOrderMetaData() :
              m_pNode(NULL)
          {}
  
          ///
          // Ctor - creates the empty, named SubGroupSizeMetaData object
          //
          WorkgroupWalkOrderMetaData::WorkgroupWalkOrderMetaData(const char* name) :
              _Mybase(name),
              m_pNode(NULL)
          {}
  
          bool WorkgroupWalkOrderMetaData::hasValue() const
          {
              if (m_Dim0.hasValue())
              {
                  return true;
              }
  
              if (m_Dim1.hasValue())
              {
                  return true;
              }
  
              if (m_Dim2.hasValue())
              {
                  return true;
              }
  
              return NULL != m_pNode || dirty();
          }
  
          ///
          // Returns true if any of the SubGroupSizeMetaData`s members has changed
          bool WorkgroupWalkOrderMetaData::dirty() const
          {
              if (m_Dim0.dirty())
              {
                  return true;
              }
  
              if (m_Dim1.dirty())
              {
                  return true;
              }
  
              if (m_Dim2.dirty())
              {
                  return true;
              }
              return false;
          }
  
          ///
          // Discards the changes done to the SubGroupSizeMetaData instance
          void WorkgroupWalkOrderMetaData::discardChanges()
          {
              m_Dim0.discardChanges();
              m_Dim1.discardChanges();
              m_Dim2.discardChanges();
          }
  
          ///
          // Generates the new MDNode hierarchy for the given structure
          llvm::Metadata* WorkgroupWalkOrderMetaData::generateNode(llvm::LLVMContext& context) const
          {
              llvm::SmallVector<llvm::Metadata*, 5> args;
  
              llvm::Metadata* pIDNode = _Mybase::generateNode(context);
              if (NULL != pIDNode)
              {
                  args.push_back(pIDNode);
              }
  
              args.push_back(m_Dim0.generateNode(context));
              args.push_back(m_Dim1.generateNode(context));
              args.push_back(m_Dim2.generateNode(context));
  
              return llvm::MDNode::get(context, args);
          }
  
          ///
          // Saves the structure changes to the given MDNode
          void WorkgroupWalkOrderMetaData::save(llvm::LLVMContext& context, llvm::MDNode* pNode) const
          {
              IGC_ASSERT_MESSAGE(nullptr != pNode, "The target node should be valid pointer");
  
              // we assume that underlying metadata node has not changed under our foot
              if (pNode == m_pNode && !dirty())
              {
                  return;
              }
  #if 0
              // check that we could save the new information to the given node without regenerating it
              if (!compatibleWith(pNode))
              {
                  pNode->replaceAllUsesWith(generateNode(context));
                  return;
              }
  #endif
  
              m_Dim0.save(context, llvm::cast<llvm::MDNode>(getDim0Node(pNode)));
              m_Dim1.save(context, llvm::cast<llvm::MDNode>(getDim1Node(pNode)));
              m_Dim2.save(context, llvm::cast<llvm::MDNode>(getDim2Node(pNode)));
          }
  
          llvm::Metadata* WorkgroupWalkOrderMetaData::getDim0Node(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(0 + offset).get();
          }
  
          llvm::Metadata* WorkgroupWalkOrderMetaData::getDim1Node(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(1 + offset).get();
          }
  
          llvm::Metadata* WorkgroupWalkOrderMetaData::getDim2Node(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(2 + offset).get();
          }
  
  
          ///
          // Ctor - loads the KernelMetaData from the given metadata node
          //
          KernelMetaData::KernelMetaData(const llvm::MDNode* pNode, bool hasId) :
              _Mybase(pNode, hasId),
              m_Function(getFunctionNode(pNode)),
              m_WorkGroupSizeHint(WorkGroupDimensionsMetaData::get(getWorkGroupSizeHintNode(pNode), true)),
              m_RequiredWorkGroupSize(WorkGroupDimensionsMetaData::get(getRequiredWorkGroupSizeNode(pNode), true)),
              m_RequiredSubGroupSize(SubGroupDimensionsMetaData::get(getRequiredSubGroupSizeNode(pNode), true)),
              m_WorkgroupWalkOrder(WorkgroupWalkOrderMetaData::get(getWorkgroupWalkOrderNode(pNode), true)),
              m_VectorTypeHint(VectorTypeHintMetaData::get(getVectorTypeHintNode(pNode), true)),
              m_ArgAddressSpaces(getArgAddressSpacesNode(pNode), true),
              m_ArgAccessQualifiers(getArgAccessQualifiersNode(pNode), true),
              m_ArgTypes(getArgTypesNode(pNode), true),
              m_ArgBaseTypes(getArgBaseTypesNode(pNode), true),
              m_ArgTypeQualifiers(getArgTypeQualifiersNode(pNode), true),
              m_ArgNames(getArgNamesNode(pNode), true),
              m_pNode(pNode)
          {}
  
          ///
          // Default Ctor - creates the empty, not named KernelMetaData object
          //
          KernelMetaData::KernelMetaData() : m_WorkGroupSizeHint(WorkGroupDimensionsMetaDataHandle::ObjectType::get("work_group_size_hint")),
              m_RequiredWorkGroupSize(WorkGroupDimensionsMetaDataHandle::ObjectType::get("reqd_work_group_size")),
              m_RequiredSubGroupSize(SubGroupDimensionsMetaDataHandle::ObjectType::get("intel_reqd_sub_group_size")),
              m_WorkgroupWalkOrder(WorkgroupWalkOrderMetaDataHandle::ObjectType::get("intel_reqd_workgroup_walk_order")),
              m_VectorTypeHint(VectorTypeHintMetaDataHandle::ObjectType::get("vec_type_hint")),
              m_ArgAddressSpaces("kernel_arg_addr_space"),
              m_ArgAccessQualifiers("kernel_arg_access_qual"),
              m_ArgTypes("kernel_arg_type"),
              m_ArgBaseTypes("kernel_arg_base_type"),
              m_ArgTypeQualifiers("kernel_arg_type_qual"),
              m_ArgNames("kernel_arg_name"),
              m_pNode(NULL)
          {}
  
          ///
          // Ctor - creates the empty, named KernelMetaData object
          //
          KernelMetaData::KernelMetaData(const char* name) :
              _Mybase(name), m_WorkGroupSizeHint(WorkGroupDimensionsMetaDataHandle::ObjectType::get("work_group_size_hint")),
              m_RequiredWorkGroupSize(WorkGroupDimensionsMetaDataHandle::ObjectType::get("reqd_work_group_size")),
              m_RequiredSubGroupSize(SubGroupDimensionsMetaDataHandle::ObjectType::get("intel_reqd_sub_group_size")),
              m_WorkgroupWalkOrder(WorkgroupWalkOrderMetaDataHandle::ObjectType::get("intel_reqd_workgroup_walk_order")),
              m_VectorTypeHint(VectorTypeHintMetaDataHandle::ObjectType::get("vec_type_hint")),
              m_ArgAddressSpaces("kernel_arg_addr_space"),
              m_ArgAccessQualifiers("kernel_arg_access_qual"),
              m_ArgTypes("kernel_arg_type"),
              m_ArgBaseTypes("kernel_arg_base_type"),
              m_ArgTypeQualifiers("kernel_arg_type_qual"),
              m_ArgNames("kernel_arg_name"),
              m_pNode(NULL)
          {}
  
          bool KernelMetaData::hasValue() const
          {
              if (m_Function.hasValue())
              {
                  return true;
              }
  
  
              if (m_WorkGroupSizeHint->hasValue())
              {
                  return true;
              }
  
  
              if (m_RequiredWorkGroupSize->hasValue())
              {
                  return true;
              }
  
  
              if (m_RequiredSubGroupSize->hasValue())
              {
                  return true;
              }
  
              if (m_WorkgroupWalkOrder->hasValue())
              {
                  return true;
              }
  
  
              if (m_VectorTypeHint->hasValue())
              {
                  return true;
              }
  
  
              if (m_ArgAddressSpaces.hasValue())
              {
                  return true;
              }
  
  
              if (m_ArgAccessQualifiers.hasValue())
              {
                  return true;
              }
  
  
              if (m_ArgTypes.hasValue())
              {
                  return true;
              }
  
  
              if (m_ArgBaseTypes.hasValue())
              {
                  return true;
              }
  
  
              if (m_ArgTypeQualifiers.hasValue())
              {
                  return true;
              }
  
  
              if (m_ArgNames.hasValue())
              {
                  return true;
              }
              return NULL != m_pNode || dirty();
          }
  
          ///
          // Returns true if any of the KernelMetaData`s members has changed
          bool KernelMetaData::dirty() const
          {
              if (m_Function.dirty())
              {
                  return true;
              }
              if (m_WorkGroupSizeHint.dirty())
              {
                  return true;
              }
              if (m_RequiredWorkGroupSize.dirty())
              {
                  return true;
              }
              if (m_RequiredSubGroupSize.dirty())
              {
                  return true;
              }
              if (m_WorkgroupWalkOrder.dirty())
              {
                  return true;
              }
              if (m_VectorTypeHint.dirty())
              {
                  return true;
              }
              if (m_ArgAddressSpaces.dirty())
              {
                  return true;
              }
              if (m_ArgAccessQualifiers.dirty())
              {
                  return true;
              }
              if (m_ArgTypes.dirty())
              {
                  return true;
              }
              if (m_ArgBaseTypes.dirty())
              {
                  return true;
              }
              if (m_ArgTypeQualifiers.dirty())
              {
                  return true;
              }
              if (m_ArgNames.dirty())
              {
                  return true;
              }
              return false;
          }
  
          ///
          // Discards the changes done to the KernelMetaData instance
          void KernelMetaData::discardChanges()
          {
              m_Function.discardChanges();
              m_WorkGroupSizeHint.discardChanges();
              m_RequiredWorkGroupSize.discardChanges();
              m_RequiredSubGroupSize.discardChanges();
              m_WorkgroupWalkOrder.discardChanges();
              m_VectorTypeHint.discardChanges();
              m_ArgAddressSpaces.discardChanges();
              m_ArgAccessQualifiers.discardChanges();
              m_ArgTypes.discardChanges();
              m_ArgBaseTypes.discardChanges();
              m_ArgTypeQualifiers.discardChanges();
              m_ArgNames.discardChanges();
          }
  
          ///
          // Generates the new MDNode hierarchy for the given structure
          llvm::Metadata* KernelMetaData::generateNode(llvm::LLVMContext& context) const
          {
              llvm::SmallVector<llvm::Metadata*, 5> args;
  
              llvm::Metadata* pIDNode = _Mybase::generateNode(context);
              if (NULL != pIDNode)
              {
                  args.push_back(pIDNode);
              }
  
              args.push_back(m_Function.generateNode(context));
              if (m_WorkGroupSizeHint->hasValue())
              {
                  args.push_back(m_WorkGroupSizeHint.generateNode(context));
              }
  
              if (m_RequiredWorkGroupSize->hasValue())
              {
                  args.push_back(m_RequiredWorkGroupSize.generateNode(context));
              }
  
              if (m_RequiredSubGroupSize->hasValue())
              {
                  args.push_back(m_RequiredSubGroupSize.generateNode(context));
              }
  
              if (m_WorkgroupWalkOrder->hasValue())
              {
                  args.push_back(m_WorkgroupWalkOrder.generateNode(context));
              }
  
              if (m_VectorTypeHint->hasValue())
              {
                  args.push_back(m_VectorTypeHint.generateNode(context));
              }
  
              args.push_back(m_ArgAddressSpaces.generateNode(context));
              args.push_back(m_ArgAccessQualifiers.generateNode(context));
              args.push_back(m_ArgTypes.generateNode(context));
              args.push_back(m_ArgBaseTypes.generateNode(context));
              args.push_back(m_ArgTypeQualifiers.generateNode(context));
              if (isArgNamesHasValue())
              {
                  args.push_back(m_ArgNames.generateNode(context));
              }
  
              return llvm::MDNode::get(context, args);
          }
  
          ///
          // Saves the structure changes to the given MDNode
          void KernelMetaData::save(llvm::LLVMContext& context, llvm::MDNode* pNode) const
          {
              IGC_ASSERT_MESSAGE(nullptr != pNode, "The target node should be valid pointer");
  
              // we assume that underlying metadata node has not changed under our foot
              if (pNode == m_pNode && !dirty())
              {
                  return;
              }
  #if 0
              // check that we could save the new information to the given node without regenerating it
              if (!compatibleWith(pNode))
              {
                  pNode->replaceAllUsesWith(generateNode(context));
                  return;
              }
  #endif
  
              m_Function.save(context, llvm::cast<llvm::MDNode>(getFunctionNode(pNode)));
              m_WorkGroupSizeHint.save(context, llvm::cast<llvm::MDNode>(getWorkGroupSizeHintNode(pNode)));
              m_RequiredWorkGroupSize.save(context, llvm::cast<llvm::MDNode>(getRequiredWorkGroupSizeNode(pNode)));
              m_RequiredSubGroupSize.save(context, llvm::cast<llvm::MDNode>(getRequiredSubGroupSizeNode(pNode)));
              m_WorkgroupWalkOrder.save(context, llvm::cast<llvm::MDNode>(getWorkgroupWalkOrderNode(pNode)));
              m_VectorTypeHint.save(context, llvm::cast<llvm::MDNode>(getVectorTypeHintNode(pNode)));
              m_ArgAddressSpaces.save(context, llvm::cast<llvm::MDNode>(getArgAddressSpacesNode(pNode)));
              m_ArgAccessQualifiers.save(context, llvm::cast<llvm::MDNode>(getArgAccessQualifiersNode(pNode)));
              m_ArgTypes.save(context, llvm::cast<llvm::MDNode>(getArgTypesNode(pNode)));
              m_ArgBaseTypes.save(context, llvm::cast<llvm::MDNode>(getArgBaseTypesNode(pNode)));
              m_ArgTypeQualifiers.save(context, llvm::cast<llvm::MDNode>(getArgTypeQualifiersNode(pNode)));
              m_ArgNames.save(context, llvm::cast<llvm::MDNode>(getArgNamesNode(pNode)));
          }
  
          llvm::Metadata* KernelMetaData::getFunctionNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              return pParentNode->getOperand(0 + offset).get();
          }
  
          llvm::MDNode* KernelMetaData::getWorkGroupSizeHintNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "work_group_size_hint"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getRequiredWorkGroupSizeNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "reqd_work_group_size"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getRequiredSubGroupSizeNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "intel_reqd_sub_group_size"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getWorkgroupWalkOrderNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "intel_reqd_workgroup_walk_order"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getVectorTypeHintNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "vec_type_hint"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getArgAddressSpacesNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "kernel_arg_addr_space"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getArgAccessQualifiersNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "kernel_arg_access_qual"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getArgTypesNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "kernel_arg_type"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getArgBaseTypesNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "kernel_arg_base_type"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getArgTypeQualifiersNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "kernel_arg_type_qual"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
          llvm::MDNode* KernelMetaData::getArgNamesNode(const llvm::MDNode* pParentNode) const
          {
              if (!pParentNode)
              {
                  return NULL;
              }
  
              unsigned int offset = _Mybase::getStartIndex();
              for (NodeIterator i = NodeIterator(pParentNode, 1 + offset), e = NodeIterator(pParentNode); i != e; ++i)
              {
                  if (isNamedNode(i.get(), "kernel_arg_name"))
                  {
                      return llvm::dyn_cast<llvm::MDNode>(i.get());
                  }
              }
              return NULL;
          }
  
  
          ///
          // dtor
          //SpirMetaDataUtils::~SpirMetaDataUtils()
          //{
             //
          //}
  
          static bool isNamedNode(const llvm::Metadata* pNode, const char* name)
          {
              const llvm::MDNode* pMDNode = llvm::dyn_cast<llvm::MDNode>(pNode);
  
              if (!pMDNode)
              {
                  return false;
              }
  
              if (pMDNode->getNumOperands() < 1)
              {
                  return false;
              }
  
              const llvm::MDString* pIdNode = llvm::dyn_cast<const llvm::MDString>(pMDNode->getOperand(0));
              if (!pIdNode)
              {
                  return false;
              }
  
              llvm::StringRef id = pIdNode->getString();
              if (id.compare(name))
              {
                  return false;
              }
              return true;
          }
  
      }
  }
  