From 4d486c0e5cac8c5153674c9ceacd46084d096423 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 21 Jun 2024 14:05:49 -0400 Subject: [PATCH] xo-expression: + Primitive::intrinsic --- example/ex1/ex1.cpp | 5 ++- include/xo/expression/Primitive.hpp | 37 +++++++++++++------- include/xo/expression/PrimitiveInterface.hpp | 7 ++-- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/example/ex1/ex1.cpp b/example/ex1/ex1.cpp index be606918..5dd91fe2 100644 --- a/example/ex1/ex1.cpp +++ b/example/ex1/ex1.cpp @@ -2,6 +2,7 @@ #include "xo/expression/Constant.hpp" #include "xo/expression/Primitive.hpp" +#include "xo/expression/llvmintrinsic.hpp" #include #include @@ -9,6 +10,7 @@ int main() { using xo::ast::make_constant; using xo::ast::make_primitive; + using xo::ast::llvmintrinsic; using std::cout; using std::endl; @@ -19,7 +21,8 @@ main() { { auto expr = make_primitive("sqrt", &::sqrt, - false /*!explicit_symbol_def*/); + false /*!explicit_symbol_def*/, + llvmintrinsic::fp_sqrt); auto expr_td = expr->value_td(); diff --git a/include/xo/expression/Primitive.hpp b/include/xo/expression/Primitive.hpp index caf7f1bf..49246d8b 100644 --- a/include/xo/expression/Primitive.hpp +++ b/include/xo/expression/Primitive.hpp @@ -6,6 +6,7 @@ #pragma once #include "PrimitiveInterface.hpp" +#include "llvmintrinsic.hpp" #include "xo/reflect/Reflect.hpp" //#include @@ -15,9 +16,11 @@ namespace xo { * @brief syntax for a constant that refers to a known function. * * Two cases here: - * 1. primitive refers to a function that is supported directly in llvm - * (e.g. floating-point addition) - * 2. primitive refers to a compiled (C/C++) function that we can invoke at runtime + * 1. (always) primitive refers to a compiled (C/C++) function that we can invoke at runtime + * 2. (sometimes) primitive also refers to a function that is supported directly in llvm + * (e.g. floating-point addition). In that case @ref intrinsic_ + * identifies that direct support, provided it knows at codegen time which primitive + * is being invoked * * In any case, a primitive serves as both declaration and definition * (May be possible to relax this to declaration-only using null value_ as sentinel..?) @@ -36,13 +39,15 @@ namespace xo { public: static ref::rp make(const std::string & name, FunctionPointer fnptr, - bool explicit_symbol_def) { + bool explicit_symbol_def, + llvmintrinsic intrinsic) { TypeDescr fn_type = Reflect::require(); - return new Primitive(fn_type, name, fnptr, explicit_symbol_def); + return new Primitive(fn_type, name, fnptr, explicit_symbol_def, intrinsic); } FunctionPointer value() const { return value_; } + llvmintrinsic intrinsic() const { return intrinsic_; } TypeDescr value_td() const { return value_td_; } TaggedPtr value_tp() const { @@ -79,12 +84,14 @@ namespace xo { Primitive(TypeDescr fn_type, const std::string & name, FunctionPointer fnptr, - bool explicit_symbol_def) + bool explicit_symbol_def, + llvmintrinsic intrinsic) : PrimitiveInterface(fn_type), name_{name}, value_td_{Reflect::require_function()}, value_{fnptr}, - explicit_symbol_def_{explicit_symbol_def} + explicit_symbol_def_{explicit_symbol_def}, + intrinsic_{intrinsic} { if (!value_td_->is_function()) throw std::runtime_error("Primitive: expected function pointer"); @@ -103,11 +110,16 @@ namespace xo { TypeDescr value_td_; /** address of executable function **/ FunctionPointer value_; - /** if true, use Jit.intern_symbol() to provide explicit binding. - * Currently mystified as to what's distinguishes functions like ::sin(), ::sqrt() - * (which work do not require this) from symbols like ::mul_i32(), which do) + /** for LLVM: if true, use Jit.intern_symbol() to provide explicit binding. + * + * Not obvious what distinguishes functions like ::sin(), ::sqrt() + * (which work without this) from symbols like ::mul_i32(), which do. **/ bool explicit_symbol_def_ = false; + /** invalid: generate call (IRBuilder::CreateCall) + * all others: generate direct use of LLVM intrinsic + **/ + llvmintrinsic intrinsic_; }; /*Primitive*/ /** adopt function @p x as a callable primitive function named @p name **/ @@ -115,9 +127,10 @@ namespace xo { ref::rp> make_primitive(const std::string & name, FunctionPointer x, - bool explicit_symbol_def) + bool explicit_symbol_def, + llvmintrinsic intrinsic) { - return Primitive::make(name, x, explicit_symbol_def); + return Primitive::make(name, x, explicit_symbol_def, intrinsic); } } /*namespace ast*/ } /*namespace xo*/ diff --git a/include/xo/expression/PrimitiveInterface.hpp b/include/xo/expression/PrimitiveInterface.hpp index 0b42b252..629772e0 100644 --- a/include/xo/expression/PrimitiveInterface.hpp +++ b/include/xo/expression/PrimitiveInterface.hpp @@ -6,6 +6,7 @@ #pragma once #include "FunctionInterface.hpp" +#include "llvmintrinsic.hpp" //#include @@ -34,10 +35,12 @@ namespace xo { **/ virtual bool explicit_symbol_def() const = 0; - /** function address for this primitive - **/ + /** function address for this primitive **/ virtual void_function_type function_address() const = 0; + /** get llvm intrinsic hint for this primitive **/ + virtual llvmintrinsic intrinsic() const = 0; + // virtual const std::string & name() const; // virtual int n_arg() const; // virtual TypeDescr fn_retval() const;