htvm-0.1.1: src/HTVM/EDSL/Printer.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}
module HTVM.EDSL.Printer where
import qualified Data.Text as Text
import Control.Monad.Writer(MonadWriter,Writer,tell,execWriter)
import Data.Monoid((<>))
import Data.Maybe(fromJust)
import Data.Text(Text)
import HTVM.Prelude
import HTVM.EDSL.Types
import HTVM.EDSL.Monad
printDimExpr :: DimExpr -> Text
printDimExpr se =
let
go = printDimExpr
in
case se of
DimConst i -> tshow i
DimId n -> printName n
DimCall nm es
| isOpName nm && length es == 2 -> go (es!!0) <> printName nm <> go (es!!1)
| isOpName nm && length es == 1 -> printName nm <> go (es!!0)
| otherwise -> printName nm <> "(" <> Text.intercalate "," (map go es) <> ")"
DimCtr n -> "tvm::var(\"" <> n <> "\")"
printShapeExpr :: ShapeExpr -> Text
printShapeExpr se =
let
go = printShapeExpr
in
case se of
ShapeTen te -> "htvm_shape("<> printTenExpr te <> ")"
ShapeVector de -> "{" <> printDimExpr de <> "}"
ShapeScalar -> "{}"
ShapeSum se1 se2 -> "htvm_shape_concat("<> go se1 <> "," <> go se2 <> ")"
printExprFuncName :: ExprFuncName -> Text
printExprFuncName fn =
case fn of
ExprSum -> "tvm::sum"
ExprOp op -> op
ESigmoid -> "tvm::sigmoid"
printExpr :: Expr -> Text
printExpr e =
let
go = printExpr
in
case e of
EId n -> printName n
EConst c ->
case c of
CInt i -> tshow i
CFloat32 f -> tshow f
ECall nm es ->
case nm of
ExprOp _
| length es == 2 -> go (es!!0) <> printExprFuncName nm <> go (es!!1)
| length es == 1 -> printExprFuncName nm <> go (es!!0)
_ -> printExprFuncName nm <> "(" <> Text.intercalate "," (map go es) <> ")"
ETenSlice te es -> printTenExpr te <> "(" <> Text.intercalate "," (map go es) <> ")"
EShapeSlice se sl -> printShapeExpr se <> "[" <> tshow sl <> "]"
ESlice e i -> go e <> "[" <> tshow i <> "]"
ETuple es -> "{" <> Text.intercalate "," (map go es) <> "}"
printName :: Name -> Text
printName (Name n) = n -- TODO: escape to make C-compatible
isOpName :: Name -> Bool
isOpName (Name n) = n`Text.isInfixOf`"+-*/"
printPattern :: Pattern -> Text
printPattern p =
case p of
PTensor n -> "tvm::Tensor " <> printName n
PShape n -> "tvm::Array<tvm::Expr> " <> printName n
PVar n -> "tvm::Var " <> printName n
PIterVar n -> "tvm::IterVar " <> printName n
PFunc n -> "tvm::LoweredFunc " <> printName n
PAxis n -> "tvm::Array<tvm::Var> " <> printName n
PTenTuple n -> "tvm::Array<tvm::Tensor> " <> printName n
PFuncTuple n -> "tvm::Array<tvm::LoweredFunc> " <> printName n
PSchedule n -> "tvm::Schedule " <> printName n
PStage n -> "tvm::Stage " <> printName n
printType :: Type -> Text
printType t =
case t of
TypeFloat32 -> "tvm::Float(32)"
TypeInt32 -> "tvm::Int(32)"
TypeTensor _ _ -> "tvm::Tensor()"
printTenFuncName :: TenFuncName -> Text
printTenFuncName fn =
case fn of
TenOp op -> op
TenReduceAxis -> "tvm::reduce_axis"
TenConv2d_NCHW -> "topi::conv2d_nchw"
TenPad -> "topi::pad"
TenSchedule -> "htvm_create_schedule"
TenParallel -> "htvm_parallel"
TenAxisId -> "htvm_axis_id"
TenMatMul -> "topi::matmul"
TenElemwise x -> "topi::"<>x
TenSplit -> "topi::split"
TenDifferentiate -> "htvm_differentiate"
printLayout :: Layout -> Text
printLayout l =
case l of
NCHW -> "NCHW"
NWCN -> "NWCN"
NHWC -> "NHWC"
printTenExpr :: TenExpr -> Text
printTenExpr te =
let
go = printTenExpr
parg arg =
case arg of
TenArg e -> go e
StrArg str -> "\"" <> str <> "\""
TypeArg t -> printType t
IntArg i -> tshow i
IntsArg is -> "{" <> (Text.intercalate "," (map tshow is)) <> "}"
LayoutArg l -> printLayout l
in
case te of
TenPlh (n,ty,s) -> "tvm::placeholder(" <> printShapeExpr s <> "," <> printType ty <> ",\""<>n<>"\")"
TenId n -> printName n
TenLet pat e1@(TenLet _ _ _) e2 -> printPattern pat <> " = ({" <> go e1 <> "; });\n" <> go e2
TenLet pat e1 e2 -> printPattern pat <> " = " <> go e1 <> ";\n" <> go e2
-- TenAxis (a,b) -> --error "printTenExpr: Axis (aka `tvm::IterVar`) is not implemented"
-- "tvm::reduce_axis({ " <> printDimExpr a <> "," <> printDimExpr b <> "})"
TenTuple es -> "{" <> Text.intercalate ", " (map go es) <> "}"
TenSlice te i -> go te <> "[" <> tshow i <> "]"
TenDim s -> printDimExpr s
TenShape s -> printShapeExpr s
TenExpr e -> printExpr e
TenCompute sh p e -> "tvm::compute(" <> printShapeExpr sh <> ", tvm::FBatchCompute([=](" <> printPattern p <> ") { return tvm::Array<tvm::Expr>(" <> printExpr e <> "); }))"
TenDef n te ->
execWriter $ do
line $ "({"
line $ "tvm::BuildConfig config = tvm::build_config();"
line $ "auto args = ({" <> go te <> "; });"
line $ "tvm::Schedule s = tvm::create_schedule({args[args.size()-1]->op});"
line $ "std::unordered_map<tvm::Tensor, tvm::Buffer> binds;"
line $ "auto f = tvm::Array<tvm::Tensor>(args);"
line $ "auto lowered = tvm::lower(s, f, \"" <> n <> "\", binds, config);"
line $ "lowered[0];"
line $ "})"
TenCall nm es ->
case nm of
TenOp _
| (length es == 2) -> parg (es!!0) <> printTenFuncName nm <> parg (es!!1)
| (length es == 1) -> printTenFuncName nm <> parg (es!!0)
_ -> printTenFuncName nm <> "(" <> Text.intercalate ", " (map parg es) <> ")" -- FIXME: attrs?
line :: (MonadWriter Text m) => Text -> m ()
line x = tell (x <> "\n")
printModule:: Module -> Text
printModule (Module _ te) =
execWriter $ do
line $ "({"
line $ "tvm::Array<tvm::LoweredFunc> funcs = ({" <> printTenExpr te <> "; });"
line $ "tvm::BuildConfig config = tvm::build_config();"
line $ "auto target = tvm::Target::create(\"llvm\"); "
line $ "auto target_host = tvm::Target::create(\"llvm\");"
line $ "tvm::runtime::Module mod = tvm::build(funcs, target, target_host, config);"
line $ "mod;"
line $ "})"
printIncludes :: Writer Text ()
printIncludes = do
line $ "#include <iostream>"
line $ "#include <random>"
line $ "#include <iomanip>"
line $ "#include <array>"
line $ "#include <exception>"
line $ "#include <tvm/tvm.h>"
line $ "#include <tvm/operation.h>"
line $ "#include <tvm/tensor.h>"
line $ "#include <tvm/build_module.h>"
line $ "#include <topi/broadcast.h>"
line $ "#include <topi/nn.h>"
line $ "#include <topi/elemwise.h>"
line $ "#include <topi/transform.h>"
line $ "#include <tvm/autodiff.h>"
line $ ""
line $
"static inline tvm::Array<tvm::Expr> \
\htvm_shape_concat(const tvm::Array<tvm::Expr> &s1, const tvm::Array<tvm::Expr> &s2) {\
\\
\ tvm::Array<tvm::Expr> res(s1);\
\ for(int i=0; i<s2.size(); i++) {\
\ res.push_back(s2[i]);\
\ }\
\\
\ return res;\
\}"
line $
"tvm::Schedule \
\htvm_create_schedule(const tvm::Array<tvm::Tensor> &arr) {\
\ tvm::Array<tvm::Operation> ops;\
\ for(auto a : arr) { ops.push_back(a->op); }\
\ return tvm::create_schedule(ops);\
\}"
line $ "tvm::Stage htvm_parallel(tvm::Schedule s, tvm::Tensor t, tvm::IterVar i) { return s[t->op].parallel(i); }"
line $ "tvm::IterVar htvm_axis_id(tvm::Tensor t, int i) { return t->op->root_iter_vars()[i]; }"
line $ "tvm::Array<tvm::Expr> htvm_shape(tvm::Tensor t) { return t->shape; }"
line $ "tvm::Array<tvm::Expr> htvm_shape(tvm::Array<tvm::Expr> t) { return t; }"
line $ "tvm::Array<tvm::Tensor> htvm_differentiate(tvm::Tensor t, tvm::Array<tvm::Tensor> a){ return tvm::ir::Differentiate(t,a)->result; }"
line $ ""
printModuleGen :: Module -> ModuleGenSrc
printModuleGen mod =
ModuleGenSrc mod $ execWriter $ do
printIncludes
line $ "int main()"
line $ "{"
line $ "auto mod = " <> printModule mod <> ";"
line $ "std::cout << mod->GetSource(\"asm\") << std::endl;"
line $ "}"
printPrinter :: TenExpr -> ProgramSrc
printPrinter te =
ProgramSrc $ execWriter $ do
printIncludes
line $ "int main()"
line $ "{"
line $ "auto te = ({" <> printTenExpr te <> "; });"
line $ "std::cout << te->body << std::endl;"
line $ "}"