tbaeder created this revision.
tbaeder added reviewers: erichkeane, aaron.ballman, shafik, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add a `Call` op and use the existing infrastructure for parameters and return 
values.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132286

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Context.h
  clang/lib/AST/Interp/EvalEmitter.cpp
  clang/lib/AST/Interp/Function.h
  clang/lib/AST/Interp/Interp.cpp
  clang/lib/AST/Interp/InterpFrame.cpp
  clang/lib/AST/Interp/Opcodes.td
  clang/lib/AST/Interp/PrimType.h
  clang/test/AST/Interp/functions.cpp

Index: clang/test/AST/Interp/functions.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/functions.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify %s
+// RUN: %clang_cc1 -std=c++14 -verify=ref %s
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+template<typename T> constexpr T identity(T t) { return t; }
+static_assert(identity(true), "");
+static_assert(identity(true), "");
+static_assert(!identity(false), "");
+
+
+constexpr int sub(int a, int b) {
+  return a - b;
+}
+static_assert(sub(5, 2) == 3, "");
+static_assert(sub(0, 5) == -5, "");
+
+constexpr int norm(int n) {
+  if (n >= 0) {
+    return identity(n);
+  }
+  return -identity(n);
+}
+static_assert(norm(5) == norm(-5), "");
+
+constexpr int square(int n) {
+  return norm(n) * norm(n);
+}
+static_assert(square(2) == 4, "");
+
+constexpr int add_second(int a, int b, bool doAdd) {
+  if (doAdd)
+    return a + b;
+  return a;
+}
+static_assert(add_second(10, 3, true) == 13, "");
+static_assert(add_second(300, -20, false) == 300, "");
Index: clang/lib/AST/Interp/PrimType.h
===================================================================
--- clang/lib/AST/Interp/PrimType.h
+++ clang/lib/AST/Interp/PrimType.h
@@ -82,6 +82,7 @@
 /// The macro implicitly exposes a type T in the scope of the inner block.
 #define TYPE_SWITCH_CASE(Name, B) \
   case Name: { using T = PrimConv<Name>::T; B; break; }
+
 #define TYPE_SWITCH(Expr, B)                                                   \
   do {                                                                         \
     switch (Expr) {                                                            \
Index: clang/lib/AST/Interp/Opcodes.td
===================================================================
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -42,7 +42,7 @@
 def ArgUint64 : ArgType { let Name = "uint64_t"; }
 def ArgBool : ArgType { let Name = "bool"; }
 
-def ArgFunction : ArgType { let Name = "Function *"; }
+def ArgFunction : ArgType { let Name = "const Function *"; }
 def ArgRecord : ArgType { let Name = "Record *"; }
 
 def ArgSema : ArgType { let Name = "const fltSemantics *"; }
@@ -153,6 +153,17 @@
 // [] -> EXIT
 def NoRet : Opcode {}
 
+
+def Call : Opcode {
+  let Args = [ArgFunction];
+  let Types = [AllTypeClass];
+  let ChangesPC = 1;
+  let CanReturn = 1;
+  let HasCustomEval = 1;
+  let HasGroup = 1;
+}
+
+
 //===----------------------------------------------------------------------===//
 // Frame management
 //===----------------------------------------------------------------------===//
Index: clang/lib/AST/Interp/InterpFrame.cpp
===================================================================
--- clang/lib/AST/Interp/InterpFrame.cpp
+++ clang/lib/AST/Interp/InterpFrame.cpp
@@ -171,6 +171,7 @@
   auto Memory = std::make_unique<char[]>(BlockSize);
   auto *B = new (Memory.get()) Block(Desc.second);
 
+  assert(Args);
   // Copy the initial value.
   TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off)));
 
Index: clang/lib/AST/Interp/Interp.cpp
===================================================================
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -53,6 +53,15 @@
   return true;
 }
 
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+static bool Call(InterpState &S, CodePtr &PC, APValue &Result,
+                 const Function *Func) {
+  S.Current =
+      new InterpFrame(S, const_cast<Function *>(Func), S.Current, PC, {});
+
+  return Interpret(S, Result);
+}
+
 static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
   S.CallStackDepth--;
 
@@ -398,6 +407,7 @@
   S.Note(MD->getLocation(), diag::note_declared_at);
   return false;
 }
+
 bool Interpret(InterpState &S, APValue &Result) {
   assert(!S.Current->isRoot());
   CodePtr PC = S.Current->getPC();
Index: clang/lib/AST/Interp/Function.h
===================================================================
--- clang/lib/AST/Interp/Function.h
+++ clang/lib/AST/Interp/Function.h
@@ -62,7 +62,7 @@
 
   /// Returns the size of the function's local stack.
   unsigned getFrameSize() const { return FrameSize; }
-  /// Returns the size of the argument stackx
+  /// Returns the size of the argument stack.
   unsigned getArgSize() const { return ArgSize; }
 
   /// Returns a pointer to the start of the code.
Index: clang/lib/AST/Interp/EvalEmitter.cpp
===================================================================
--- clang/lib/AST/Interp/EvalEmitter.cpp
+++ clang/lib/AST/Interp/EvalEmitter.cpp
@@ -102,6 +102,15 @@
   return ReturnValue<T>(S.Stk.pop<T>(), Result);
 }
 
+template <PrimType OpType>
+bool EvalEmitter::emitCall(const Function *Func, const SourceInfo &Info) {
+
+  S.Current =
+      new InterpFrame(S, const_cast<Function *>(Func), S.Current, {}, {});
+  // Result of call will be on the stack and needs to be handled by the caller.
+  return Interpret(S, Result);
+}
+
 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { return true; }
 
 bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
Index: clang/lib/AST/Interp/Context.h
===================================================================
--- clang/lib/AST/Interp/Context.h
+++ clang/lib/AST/Interp/Context.h
@@ -69,7 +69,6 @@
   /// Checks a result from the interpreter.
   bool Check(State &Parent, llvm::Expected<bool> &&R);
 
-private:
   /// Current compilation context.
   ASTContext &Ctx;
   /// Interpreter stack, shared across invocations.
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -69,6 +69,7 @@
   bool VisitIntegerLiteral(const IntegerLiteral *E);
   bool VisitParenExpr(const ParenExpr *E);
   bool VisitBinaryOperator(const BinaryOperator *E);
+  bool VisitCallExpr(const CallExpr *E);
   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -9,6 +9,7 @@
 #include "ByteCodeExprGen.h"
 #include "ByteCodeEmitter.h"
 #include "ByteCodeGenError.h"
+#include "ByteCodeStmtGen.h"
 #include "Context.h"
 #include "Function.h"
 #include "PrimType.h"
@@ -593,6 +594,42 @@
   return this->bail(VD);
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
+  assert(!E->getBuiltinCallee() && "Builtin functions aren't supported yet");
+
+  const Decl *Callee = E->getCalleeDecl();
+  if (const auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(Callee)) {
+    Function *Func = P.getFunction(FuncDecl);
+
+    // Templated functions might not have been compiled yet, so do it now.
+    if (!Func) {
+      if (auto R =
+              ByteCodeStmtGen<ByteCodeEmitter>(Ctx, P).compileFunc(FuncDecl)) {
+        Func = *R;
+      }
+    }
+    assert(Func);
+
+    if (Optional<PrimType> T = classify(E->getType())) {
+      // Put arguments on the stack
+      for (const auto *Arg : E->arguments()) {
+        if (!this->visit(Arg))
+          return false;
+      }
+
+      return this->emitCall(*T, Func, E);
+    } else {
+      assert(false && "Can't classify function return type");
+    }
+
+  } else {
+    assert(false && "We don't support non-FunctionDecl callees right now.");
+  }
+
+  return false;
+}
+
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitCXXBoolLiteralExpr(
     const CXXBoolLiteralExpr *E) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to