[Clang Interpreter] Initial patch for the constexpr interpreter

Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.

Reviewers: Bigcheese, jfb, rsmith

Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D64146

llvm-svn: 371834
diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h
new file mode 100644
index 0000000..5f0012d
--- /dev/null
+++ b/clang/lib/AST/Interp/Program.h
@@ -0,0 +1,220 @@
+//===--- Program.h - Bytecode for the constexpr VM --------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a program which organises and links multiple bytecode functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H
+#define LLVM_CLANG_AST_INTERP_PROGRAM_H
+
+#include <map>
+#include <vector>
+#include "Function.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+#include "Source.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+
+namespace clang {
+class RecordDecl;
+class Expr;
+class FunctionDecl;
+class Stmt;
+class StringLiteral;
+class VarDecl;
+
+namespace interp {
+class Context;
+class State;
+class Record;
+class Scope;
+
+/// The program contains and links the bytecode for all functions.
+class Program {
+public:
+  Program(Context &Ctx) : Ctx(Ctx) {}
+
+  /// Emits a string literal among global data.
+  unsigned createGlobalString(const StringLiteral *S);
+
+  /// Returns a pointer to a global.
+  Pointer getPtrGlobal(unsigned Idx);
+
+  /// Returns the value of a global.
+  Block *getGlobal(unsigned Idx) {
+    assert(Idx < Globals.size());
+    return Globals[Idx]->block();
+  }
+
+  /// Finds a global's index.
+  llvm::Optional<unsigned> getGlobal(const ValueDecl *VD);
+
+  /// Returns or creates a global an creates an index to it.
+  llvm::Optional<unsigned> getOrCreateGlobal(const ValueDecl *VD);
+
+  /// Returns or creates a dummy value for parameters.
+  llvm::Optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
+
+  /// Creates a global and returns its index.
+  llvm::Optional<unsigned> createGlobal(const ValueDecl *VD);
+
+  /// Creates a global from a lifetime-extended temporary.
+  llvm::Optional<unsigned> createGlobal(const Expr *E);
+
+  /// Creates a new function from a code range.
+  template <typename... Ts>
+  Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
+    auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
+    Funcs.insert({Def, std::unique_ptr<Function>(Func)});
+    return Func;
+  }
+  /// Creates an anonymous function.
+  template <typename... Ts>
+  Function *createFunction(Ts &&... Args) {
+    auto *Func = new Function(*this, std::forward<Ts>(Args)...);
+    AnonFuncs.emplace_back(Func);
+    return Func;
+  }
+
+  /// Returns a function.
+  Function *getFunction(const FunctionDecl *F);
+
+  /// Returns a pointer to a function if it exists and can be compiled.
+  /// If a function couldn't be compiled, an error is returned.
+  /// If a function was not yet defined, a null pointer is returned.
+  llvm::Expected<Function *> getOrCreateFunction(const FunctionDecl *F);
+
+  /// Returns a record or creates one if it does not exist.
+  Record *getOrCreateRecord(const RecordDecl *RD);
+
+  /// Creates a descriptor for a primitive type.
+  Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
+                               bool IsConst = false,
+                               bool IsTemporary = false,
+                               bool IsMutable = false) {
+    return allocateDescriptor(D, Type, IsConst, IsTemporary, IsMutable);
+  }
+
+  /// Creates a descriptor for a composite type.
+  Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
+                               bool IsConst = false, bool IsTemporary = false,
+                               bool IsMutable = false);
+
+  /// Context to manage declaration lifetimes.
+  class DeclScope {
+  public:
+    DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
+    ~DeclScope() { P.endDeclaration(); }
+
+  private:
+    Program &P;
+  };
+
+  /// Returns the current declaration ID.
+  llvm::Optional<unsigned> getCurrentDecl() const {
+    if (CurrentDeclaration == NoDeclaration)
+      return llvm::Optional<unsigned>{};
+    return LastDeclaration;
+  }
+
+private:
+  friend class DeclScope;
+
+  llvm::Optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
+                                        bool IsStatic, bool IsExtern);
+
+  /// Reference to the VM context.
+  Context &Ctx;
+  /// Mapping from decls to cached bytecode functions.
+  llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
+  /// List of anonymous functions.
+  std::vector<std::unique_ptr<Function>> AnonFuncs;
+
+  /// Function relocation locations.
+  llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
+
+  /// Custom allocator for global storage.
+  using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
+
+  /// Descriptor + storage for a global object.
+  ///
+  /// Global objects never go out of scope, thus they do not track pointers.
+  class Global {
+  public:
+    /// Create a global descriptor for string literals.
+    template <typename... Tys>
+    Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
+
+    /// Allocates the global in the pool, reserving storate for data.
+    void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
+      return Alloc.Allocate(Meta + Data, alignof(void *));
+    }
+
+    /// Return a pointer to the data.
+    char *data() { return B.data(); }
+    /// Return a pointer to the block.
+    Block *block() { return &B; }
+
+  private:
+    /// Required metadata - does not actually track pointers.
+    Block B;
+  };
+
+  /// Allocator for globals.
+  PoolAllocTy Allocator;
+
+  /// Global objects.
+  std::vector<Global *> Globals;
+  /// Cached global indices.
+  llvm::DenseMap<const void *, unsigned> GlobalIndices;
+
+  /// Mapping from decls to record metadata.
+  llvm::DenseMap<const RecordDecl *, Record *> Records;
+
+  /// Dummy parameter to generate pointers from.
+  llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams;
+
+  /// Creates a new descriptor.
+  template <typename... Ts>
+  Descriptor *allocateDescriptor(Ts &&... Args) {
+    return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
+  }
+
+  /// No declaration ID.
+  static constexpr unsigned NoDeclaration = (unsigned)-1;
+  /// Last declaration ID.
+  unsigned LastDeclaration = 0;
+  /// Current declaration ID.
+  unsigned CurrentDeclaration = NoDeclaration;
+
+  /// Starts evaluating a declaration.
+  void startDeclaration(const VarDecl *Decl) {
+    LastDeclaration += 1;
+    CurrentDeclaration = LastDeclaration;
+  }
+
+  /// Ends a global declaration.
+  void endDeclaration() {
+    CurrentDeclaration = NoDeclaration;
+  }
+
+public:
+  /// Dumps the disassembled bytecode to \c llvm::errs().
+  void dump() const;
+  void dump(llvm::raw_ostream &OS) const;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif