xo-expression: arithmetic expression support

This commit is contained in:
Roland Conybeare 2024-08-19 18:45:02 -04:00
commit d4fd55b8ed
7 changed files with 181 additions and 2 deletions

View file

@ -28,6 +28,19 @@ namespace xo {
static rp<Apply> make(const rp<Expression> & fn, static rp<Apply> make(const rp<Expression> & fn,
const std::vector<rp<Expression>> & argv); const std::vector<rp<Expression>> & argv);
/** create apply-expression to add two 64-bit floating-point numbers **/
static rp<Apply> make_add2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs);
/** create apply-expression to subtract two 64-bit floating-point numbers **/
static rp<Apply> make_sub2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs);
/** create apply-expression to multiply two 64-bit floating-point numbers **/
static rp<Apply> make_mul2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs);
/** create apply-expression to divide two 64-bit floating-point numbers **/
static rp<Apply> make_div2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs);
/** downcast from Expression **/ /** downcast from Expression **/
static ref::brw<Apply> from(ref::brw<Expression> x) { static ref::brw<Apply> from(ref::brw<Expression> x) {
return ref::brw<Apply>::from(x); return ref::brw<Apply>::from(x);

View file

@ -10,6 +10,13 @@
#include "xo/reflect/Reflect.hpp" #include "xo/reflect/Reflect.hpp"
//#include <cstdint> //#include <cstdint>
extern "C" {
/* these symbols needed to link primitives */
/* see Primitive_f64::make() */
double add2_f64(double x, double y);
};
namespace xo { namespace xo {
namespace ast { namespace ast {
/** @class Primitive /** @class Primitive
@ -35,6 +42,7 @@ namespace xo {
using Reflect = xo::reflect::Reflect; using Reflect = xo::reflect::Reflect;
using TaggedPtr = xo::reflect::TaggedPtr; using TaggedPtr = xo::reflect::TaggedPtr;
using TypeDescr = xo::reflect::TypeDescr; using TypeDescr = xo::reflect::TypeDescr;
using fptr_type = FunctionPointer;
public: public:
static rp<Primitive> make(const std::string & name, static rp<Primitive> make(const std::string & name,
@ -46,8 +54,9 @@ namespace xo {
return new Primitive(fn_type, name, fnptr, explicit_symbol_def, intrinsic); return new Primitive(fn_type, name, fnptr, explicit_symbol_def, intrinsic);
} }
/** see classes below for intrinsics **/
FunctionPointer value() const { return value_; } FunctionPointer value() const { return value_; }
llvmintrinsic intrinsic() const { return intrinsic_; }
TypeDescr value_td() const { return value_td_; } TypeDescr value_td() const { return value_td_; }
TaggedPtr value_tp() const { TaggedPtr value_tp() const {
@ -60,6 +69,7 @@ namespace xo {
// ----- PrimitiveInterface ----- // ----- PrimitiveInterface -----
virtual llvmintrinsic intrinsic() const override { return intrinsic_; }
virtual bool explicit_symbol_def() const override { return explicit_symbol_def_; } virtual bool explicit_symbol_def() const override { return explicit_symbol_def_; }
virtual void_function_type function_address() const override { return reinterpret_cast<void_function_type>(value_); } virtual void_function_type function_address() const override { return reinterpret_cast<void_function_type>(value_); }
@ -113,7 +123,7 @@ namespace xo {
/** for LLVM: if true, use Jit.intern_symbol() to provide explicit binding. /** for LLVM: if true, use Jit.intern_symbol() to provide explicit binding.
* *
* Not obvious what distinguishes functions like ::sin(), ::sqrt() * Not obvious what distinguishes functions like ::sin(), ::sqrt()
* (which work without this) from symbols like ::mul_i32(), which do. * (which work without this) from symbols like ::mul_i32(), which require it.
**/ **/
bool explicit_symbol_def_ = false; bool explicit_symbol_def_ = false;
/** invalid: generate call (IRBuilder::CreateCall) /** invalid: generate call (IRBuilder::CreateCall)
@ -132,6 +142,21 @@ namespace xo {
{ {
return Primitive<FunctionPointer>::make(name, x, explicit_symbol_def, intrinsic); return Primitive<FunctionPointer>::make(name, x, explicit_symbol_def, intrinsic);
} }
class Primitive_f64 : public Primitive<double (*)(double, double)> {
public:
using PrimitiveType = Primitive<double (*)(double, double)>;
public:
/** add2_f64: add two 64-bit floating-point numbers **/
static rp<PrimitiveType> make_add2_f64();
/** sub2_f64: subtract two 64-bit floating-point numbers **/
static rp<PrimitiveType> make_sub2_f64();
/** mul2_f64: multiply two 64-bit floating-point numbers **/
static rp<PrimitiveType> make_mul2_f64();
/** div2_f64: divide two 64-bit floating-point numbers **/
static rp<PrimitiveType> make_div2_f64();
};
} /*namespace ast*/ } /*namespace ast*/
} /*namespace xo*/ } /*namespace xo*/

View file

@ -65,6 +65,9 @@ namespace xo {
/** -> IRBuilder::CreateFadd (add 2 floating-point numbers) **/ /** -> IRBuilder::CreateFadd (add 2 floating-point numbers) **/
fp_add, fp_add,
/** -> IRBuilder::CreateFsub (subtract 2 floating-pointer numbers) **/
fp_sub,
/** -> IRBuilder::CreateFmul (multiply 2 floating-point numbers) **/ /** -> IRBuilder::CreateFmul (multiply 2 floating-point numbers) **/
fp_mul, fp_mul,
@ -105,6 +108,7 @@ namespace xo {
case llvmintrinsic::i_sdiv: return "i_sdiv"; case llvmintrinsic::i_sdiv: return "i_sdiv";
case llvmintrinsic::i_udiv: return "i_udiv"; case llvmintrinsic::i_udiv: return "i_udiv";
case llvmintrinsic::fp_add: return "fp_add"; case llvmintrinsic::fp_add: return "fp_add";
case llvmintrinsic::fp_sub: return "fp_sub";
case llvmintrinsic::fp_mul: return "fp_mul"; case llvmintrinsic::fp_mul: return "fp_mul";
case llvmintrinsic::fp_div: return "fp_div"; case llvmintrinsic::fp_div: return "fp_div";
case llvmintrinsic::fp_sqrt: return "fp_sqrt"; case llvmintrinsic::fp_sqrt: return "fp_sqrt";

View file

@ -1,6 +1,7 @@
/* @file Apply.cpp */ /* @file Apply.cpp */
#include "Apply.hpp" #include "Apply.hpp"
#include "Primitive.hpp"
#include "xo/indentlog/print/vector.hpp" #include "xo/indentlog/print/vector.hpp"
namespace xo { namespace xo {
@ -25,6 +26,38 @@ namespace xo {
return new Apply(fn_retval_type, fn, argv); return new Apply(fn_retval_type, fn, argv);
} }
rp<Apply>
Apply::make_add2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_f64::make_add2_f64(),
{lhs, rhs});
}
rp<Apply>
Apply::make_sub2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_f64::make_sub2_f64(),
{lhs, rhs});
}
rp<Apply>
Apply::make_mul2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_f64::make_mul2_f64(),
{lhs, rhs});
}
rp<Apply>
Apply::make_div2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_f64::make_div2_f64(),
{lhs, rhs});
}
void void
Apply::display(std::ostream & os) const { Apply::display(std::ostream & os) const {
os << "<Apply" os << "<Apply"

View file

@ -10,6 +10,7 @@ set(SELF_SRCS
IfExpr.cpp IfExpr.cpp
LocalEnv.cpp LocalEnv.cpp
ConvertExpr.cpp ConvertExpr.cpp
Primitive.cpp
) )
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})

View file

@ -0,0 +1,89 @@
/* @file Primitive.cpp */
#include "Primitive.hpp"
extern "C" {
double
add2_f64(double x, double y) {
return x + y;
}
double
sub2_f64(double x, double y) {
return x - y;
}
double
mul2_f64(double x, double y) {
return x * y;
}
double
div2_f64(double x, double y) {
return x / y;
}
}
namespace xo {
namespace ast {
auto
Primitive_f64::make_add2_f64() -> rp<PrimitiveType>
{
static rp<PrimitiveType> s_retval;
if (!s_retval)
s_retval = Primitive::make("add2_f64",
&add2_f64,
true /*explicit_symbol_def*/,
llvmintrinsic::fp_add);
return s_retval;
}
auto
Primitive_f64::make_sub2_f64() -> rp<PrimitiveType>
{
static rp<PrimitiveType> s_retval;
if (!s_retval)
s_retval = Primitive::make("sub2_f64",
&sub2_f64,
true /*explicit_symbol_def*/,
llvmintrinsic::fp_sub);
return s_retval;
}
auto
Primitive_f64::make_mul2_f64() -> rp<PrimitiveType>
{
static rp<PrimitiveType> s_retval;
if (!s_retval)
s_retval = Primitive::make("mul2_f64",
&mul2_f64,
true /*explicit_symbol_def*/,
llvmintrinsic::fp_mul);
return s_retval;
}
auto
Primitive_f64::make_div2_f64() -> rp<PrimitiveType>
{
static rp<PrimitiveType> s_retval;
if (!s_retval)
s_retval = Primitive::make("div2_f64",
&div2_f64,
true /*explicit_symbol_def*/,
llvmintrinsic::fp_div);
return s_retval;
}
} /*namespace scm*/
} /*namespace xo*/
/* end Primitive.cpp */

View file

@ -0,0 +1,14 @@
/* @file intrinsics.cpp */
#include "intrinsics.hpp"
/* FIXME: don't know how to mangle symbols yet,
* so putting functions invoked from jit into global namespace
*/
extern "C"
int32_t
mul_i32(int32_t x, int32_t y) {
return x * y;
}
/* end intrinsics.cpp */