// Copyright 2018 The Clspv Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "DescriptorCounter.h"

#include <cassert>

#include "llvm/IR/Constants.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {

// We keep the current counter in a named metadata node in the module.
// It looks like this:
//
// !"clspv.descriptor.index" = !{!3}
// !3 = !{i32 0}
static const char *kMetadataName = "clspv.descriptor.index";

} // namespace

namespace clspv {

int GetCurrentDescriptorIndex(llvm::Module *M) {
  auto *md = M->getOrInsertNamedMetadata(kMetadataName);
  if (md->getNumOperands() == 0) {
    auto &ctx = M->getContext();
    IRBuilder<> Builder(ctx);
    ConstantInt *ci = Builder.getInt32(0);
    auto *val = ConstantAsMetadata::get(ci);
    md->addOperand(MDNode::get(ctx, val));
    return 0;
  }
  assert(md->getNumOperands() == 1);
  MDNode *operand = md->getOperand(0);
  assert(operand);
  assert(operand->getNumOperands() == 1);
  ConstantInt *ci = mdconst::dyn_extract<ConstantInt>(operand->getOperand(0));
  assert(ci);
  const int value = ci->getSExtValue();
  return value;
}

int TakeDescriptorIndex(llvm::Module *M) {
  const int old_value = GetCurrentDescriptorIndex(M);
  auto *md = M->getNamedMetadata(kMetadataName);
  assert(md);
  assert(md->getNumOperands() == 1);

  auto &ctx = M->getContext();
  IRBuilder<> Builder(ctx);
  md->setOperand(0, MDNode::get(ctx, ConstantAsMetadata::get(
                                         Builder.getInt32(old_value + 1))));
  return old_value;
}

} // namespace clspv
