Index: clang/lib/AST/CMakeLists.txt =================================================================== --- clang/lib/AST/CMakeLists.txt +++ clang/lib/AST/CMakeLists.txt @@ -73,6 +73,7 @@ Interp/Frame.cpp Interp/Function.cpp Interp/Interp.cpp + Interp/InterpBuiltin.cpp Interp/InterpBlock.cpp Interp/InterpFrame.cpp Interp/InterpStack.cpp Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -943,42 +943,56 @@ template bool ByteCodeExprGen::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(Callee)) { - const Function *Func = getFunction(FuncDecl); - if (!Func) - return false; - // If the function is being compiled right now, this is a recursive call. - // In that case, the function can't be valid yet, even though it will be - // later. - // If the function is already fully compiled but not constexpr, it was - // found to be faulty earlier on, so bail out. - if (Func->isFullyCompiled() && !Func->isConstexpr()) - return false; - + unsigned BuiltinID = E->getBuiltinCallee(); QualType ReturnType = E->getCallReturnType(Ctx.getASTContext()); Optional T = classify(ReturnType); - // Put arguments on the stack. - for (const auto *Arg : E->arguments()) { - if (!this->visit(Arg)) + + if (BuiltinID != 0) { + assert(*T); + FuncDecl->dump(); + + // Put arguments on the stack. + for (const auto *Arg : E->arguments()) { + if (!this->visit(Arg)) + return false; + } + return this->emitCallBI(BuiltinID, E); + + } else { + const Function *Func = getFunction(FuncDecl); + + if (!Func) + return false; + // If the function is being compiled right now, this is a recursive call. + // In that case, the function can't be valid yet, even though it will be + // later. + // If the function is already fully compiled but not constexpr, it was + // found to be faulty earlier on, so bail out. + if (Func->isFullyCompiled() && !Func->isConstexpr()) return false; - } - // Primitive return value, just call it. - if (T) - return this->emitCall(*T, Func, E); + // Put arguments on the stack. + for (const auto *Arg : E->arguments()) { + if (!this->visit(Arg)) + return false; + } - // Void Return value, easy. - if (ReturnType->isVoidType()) - return this->emitCallVoid(Func, E); + // Primitive return value, just call it. + if (T) + return this->emitCall(*T, Func, E); - // Non-primitive return value with Return Value Optimization, - // we already have a pointer on the stack to write the result into. - // TODO: Is this always the case? - if (Func->hasRVO()) - return this->emitCallVoid(Func, E); + // Void Return value, easy. + if (ReturnType->isVoidType()) + return this->emitCallVoid(Func, E); + + // Non-primitive return value with Return Value Optimization, + // we already have a pointer on the stack to write the result into. + // TODO: Is this always the case? + if (Func->hasRVO()) + return this->emitCallVoid(Func, E); + } } else { assert(false && "We don't support non-FunctionDecl callees right now."); } Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -25,6 +25,7 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "llvm/Support/Endian.h" @@ -91,6 +92,10 @@ /// Checks if a method is pure virtual. bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD); +/// Prototypes for evaluation of builtin functions. +/// Implemented in InterpBuiltin.cpp +bool InterpretBuiltinClz(InterpState &S); + template inline bool IsTrue(const T &V) { return !V.isZero(); } //===----------------------------------------------------------------------===// @@ -1090,6 +1095,16 @@ return true; } +inline bool CallBI(InterpState &S, CodePtr OpPC, uint32_t ID) { + switch (ID) { + case Builtin::BI__builtin_clz: + return InterpretBuiltinClz(S); + + default: + return false; + } +} + //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// Index: clang/lib/AST/Interp/InterpBuiltin.cpp =================================================================== --- /dev/null +++ clang/lib/AST/Interp/InterpBuiltin.cpp @@ -0,0 +1,23 @@ +//===----- InterpBuiltin.cpp - Interpret builtin functions ------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "Integral.h" +#include "InterpState.h" + +namespace clang { +namespace interp { + +bool InterpretBuiltinClz(InterpState &S) { + auto Arg = S.Stk.pop>(); + auto Result = Arg.countLeadingZeros(); + S.Stk.push>(Integral<32, true>::from(Result)); + return true; +} + +} // namespace interp +} // namespace clang Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -169,6 +169,13 @@ let HasCustomEval = 1; } +/// Call a builtin function. +def CallBI : Opcode { + let Args = [ArgUint32]; + let Types = []; + let ChangesPC = 1; +} + //===----------------------------------------------------------------------===// // Frame management //===----------------------------------------------------------------------===// Index: clang/test/AST/Interp/builtins.cpp =================================================================== --- /dev/null +++ clang/test/AST/Interp/builtins.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s +// RUN: %clang_cc1 -verify=ref %s + +// expected-no-diagnostics +// ref-no-diagnostics + + +static_assert(__builtin_clz(10) == 28, "");