/*
 * Copyright 2010-2012, The Android Open Source Project
 *
 * 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.
 */

#ifndef BCC_COMPILER_H
#define BCC_COMPILER_H

namespace llvm {

class raw_ostream;
class PassManager;
class TargetData;
class TargetMachine;

} // end namespace llvm

namespace bcc {

class CompilerConfig;
class OutputFile;
class Script;

//===----------------------------------------------------------------------===//
// Design of Compiler
//===----------------------------------------------------------------------===//
// 1. A compiler instance can be constructed provided an "initial config."
// 2. A compiler can later be re-configured using config().
// 3. Once config() is invoked, it'll re-create TargetMachine instance (i.e.,
//    mTarget) according to the configuration supplied. TargetMachine instance
//    is *shared* across the different calls to compile() before the next call
//    to config().
// 4. Once a compiler instance is created, you can use the compile() service
//    to compile the file over and over again. Each call uses TargetMachine
//    instance to construct the compilation passes.
class Compiler {
public:
  enum ErrorCode {
    kSuccess,

    kInvalidConfigNoTarget,
    kErrCreateTargetMachine,
    kErrSwitchTargetMachine,
    kErrNoTargetMachine,
    kErrTargetDataNoMemory,
    kErrMaterialization,
    kErrInvalidOutputFileState,
    kErrPrepareOutput,
    kPrepareCodeGenPass,

    kErrHookBeforeAddLTOPasses,
    kErrHookAfterAddLTOPasses,
    kErrHookBeforeExecuteLTOPasses,
    kErrHookAfterExecuteLTOPasses,

    kErrHookBeforeAddCodeGenPasses,
    kErrHookAfterAddCodeGenPasses,
    kErrHookBeforeExecuteCodeGenPasses,
    kErrHookAfterExecuteCodeGenPasses,

    kMaxErrorCode,
  };

  static const char *GetErrorString(enum ErrorCode pErrCode);

private:
  llvm::TargetMachine *mTarget;
  // LTO is enabled by default.
  bool mEnableLTO;

  enum ErrorCode runLTO(Script &pScript);
  enum ErrorCode runCodeGen(Script &pScript, llvm::raw_ostream &pResult);

public:
  Compiler();
  Compiler(const CompilerConfig &pConfig);

  enum ErrorCode config(const CompilerConfig &pConfig);

  // Compile a script and output the result to a LLVM stream.
  enum ErrorCode compile(Script &pScript, llvm::raw_ostream &pResult);

  // Compile a script and output the result to a file.
  enum ErrorCode compile(Script &pScript, OutputFile &pResult);

  const llvm::TargetMachine& getTargetMachine() const
  { return *mTarget; }

  void enableLTO(bool pEnable = true)
  { mEnableLTO = pEnable; }

  virtual ~Compiler();

protected:
  //===--------------------------------------------------------------------===//
  // Plugin callbacks for sub-class.
  //===--------------------------------------------------------------------===//
  // Called before adding first pass to code-generation passes.
  virtual bool beforeAddLTOPasses(Script &pScript, llvm::PassManager &pPM)
  { return true; }

  // Called after adding last pass to code-generation passes.
  virtual bool afterAddLTOPasses(Script &pScript, llvm::PassManager &pPM)
  { return true; }

  // Called before executing code-generation passes.
  virtual bool beforeExecuteLTOPasses(Script &pScript,
                                          llvm::PassManager &pPM)
  { return true; }

  // Called after executing code-generation passes.
  virtual bool afterExecuteLTOPasses(Script &pScript)
  { return true; }

  // Called before adding first pass to code-generation passes.
  virtual bool beforeAddCodeGenPasses(Script &pScript, llvm::PassManager &pPM)
  { return true; }

  // Called after adding last pass to code-generation passes.
  virtual bool afterAddCodeGenPasses(Script &pScript, llvm::PassManager &pPM)
  { return true; }

  // Called before executing code-generation passes.
  virtual bool beforeExecuteCodeGenPasses(Script &pScript,
                                          llvm::PassManager &pPM)
  { return true; }

  // Called after executing code-generation passes.
  virtual bool afterExecuteCodeGenPasses(Script &pScript)
  { return true; }
};

} // end namespace bcc

#endif // BCC_COMPILER_H
