{-# LANGUAGE QuasiQuotes #-}
module Futhark.CodeGen.Backends.GenericC.Server
( serverDefs,
)
where
import Data.Bifunctor (first, second)
import Data.List (unzip4)
import Data.Map qualified as M
import Data.Text qualified as T
import Futhark.CodeGen.Backends.GenericC.Options
import Futhark.CodeGen.Backends.GenericC.Pretty
import Futhark.CodeGen.Backends.SimpleRep
import Futhark.CodeGen.RTS.C (serverH, tuningH, valuesH)
import Futhark.Manifest
import Futhark.Util (zEncodeText)
import Futhark.Util.Pretty (prettyText)
import Language.C.Quote.OpenCL qualified as C
import Language.C.Syntax qualified as C
import Language.Futhark.Core (nameFromText)
genericOptions :: [Option]
genericOptions :: [Option]
genericOptions =
[ Option
{ optionLongName :: String
optionLongName = String
"debugging",
optionShortName :: Maybe Char
optionShortName = Char -> Maybe Char
forall a. a -> Maybe a
Just Char
'D',
optionArgument :: OptionArgument
optionArgument = OptionArgument
NoArgument,
optionDescription :: String
optionDescription = String
"Perform possibly expensive internal correctness checks and verbose logging.",
optionAction :: Stm
optionAction = [C.cstm|futhark_context_config_set_debugging(cfg, 1);|]
},
Option
{ optionLongName :: String
optionLongName = String
"log",
optionShortName :: Maybe Char
optionShortName = Char -> Maybe Char
forall a. a -> Maybe a
Just Char
'L',
optionArgument :: OptionArgument
optionArgument = OptionArgument
NoArgument,
optionDescription :: String
optionDescription = String
"Print various low-overhead logging information while running.",
optionAction :: Stm
optionAction = [C.cstm|futhark_context_config_set_logging(cfg, 1);|]
},
Option
{ optionLongName :: String
optionLongName = String
"profile",
optionShortName :: Maybe Char
optionShortName = Char -> Maybe Char
forall a. a -> Maybe a
Just Char
'P',
optionArgument :: OptionArgument
optionArgument = OptionArgument
NoArgument,
optionDescription :: String
optionDescription = String
"Enable the collection of profiling information.",
optionAction :: Stm
optionAction = [C.cstm|futhark_context_config_set_profiling(cfg, 1);|]
},
Option
{ optionLongName :: String
optionLongName = String
"help",
optionShortName :: Maybe Char
optionShortName = Char -> Maybe Char
forall a. a -> Maybe a
Just Char
'h',
optionArgument :: OptionArgument
optionArgument = OptionArgument
NoArgument,
optionDescription :: String
optionDescription = String
"Print help information and exit.",
optionAction :: Stm
optionAction =
[C.cstm|{
printf("Usage: %s [OPTIONS]...\nOptions:\n\n%s\nFor more information, consult the Futhark User's Guide or the man pages.\n",
fut_progname, option_descriptions);
exit(0);
}|]
},
Option
{ optionLongName :: String
optionLongName = String
"print-params",
optionShortName :: Maybe Char
optionShortName = Maybe Char
forall a. Maybe a
Nothing,
optionArgument :: OptionArgument
optionArgument = OptionArgument
NoArgument,
optionDescription :: String
optionDescription = String
"Print all tuning parameters that can be set with --param or --tuning.",
optionAction :: Stm
optionAction =
[C.cstm|{
int n = futhark_get_tuning_param_count();
for (int i = 0; i < n; i++) {
printf("%s (%s)\n", futhark_get_tuning_param_name(i),
futhark_get_tuning_param_class(i));
}
exit(0);
}|]
},
Option
{ optionLongName :: String
optionLongName = String
"param",
optionShortName :: Maybe Char
optionShortName = Maybe Char
forall a. Maybe a
Nothing,
optionArgument :: OptionArgument
optionArgument = String -> OptionArgument
RequiredArgument String
"ASSIGNMENT",
optionDescription :: String
optionDescription = String
"Set a tuning parameter to the given value.",
optionAction :: Stm
optionAction =
[C.cstm|{
char *name = optarg;
char *equals = strstr(optarg, "=");
char *value_str = equals != NULL ? equals+1 : optarg;
int value = atoi(value_str);
if (equals != NULL) {
*equals = 0;
if (futhark_context_config_set_tuning_param(cfg, name, value) != 0) {
futhark_panic(1, "Unknown parameter: %s\n", name);
}
} else {
futhark_panic(1, "Invalid argument for --parameter option: %s\n", optarg);
}}|]
},
Option
{ optionLongName :: String
optionLongName = String
"tuning",
optionShortName :: Maybe Char
optionShortName = Maybe Char
forall a. Maybe a
Nothing,
optionArgument :: OptionArgument
optionArgument = String -> OptionArgument
RequiredArgument String
"FILE",
optionDescription :: String
optionDescription = String
"Read size=value assignments from the given file.",
optionAction :: Stm
optionAction =
[C.cstm|{
char *ret = load_tuning_file(optarg, cfg, (int(*)(void*, const char*, size_t))
futhark_context_config_set_tuning_param);
if (ret != NULL) {
futhark_panic(1, "When loading tuning file '%s': %s\n", optarg, ret);
}}|]
},
Option
{ optionLongName :: String
optionLongName = String
"cache-file",
optionShortName :: Maybe Char
optionShortName = Maybe Char
forall a. Maybe a
Nothing,
optionArgument :: OptionArgument
optionArgument = String -> OptionArgument
RequiredArgument String
"FILE",
optionDescription :: String
optionDescription = String
"Store program cache here.",
optionAction :: Stm
optionAction =
[C.cstm|futhark_context_config_set_cache_file(cfg, optarg);|]
}
]
typeStructName :: T.Text -> T.Text
typeStructName :: TypeName -> TypeName
typeStructName TypeName
tname = TypeName
"type_" TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName -> TypeName
zEncodeText TypeName
tname
cType :: Manifest -> TypeName -> C.Type
cType :: Manifest -> TypeName -> Type
cType Manifest
manifest TypeName
tname =
case TypeName -> Map TypeName Type -> Maybe Type
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup TypeName
tname (Map TypeName Type -> Maybe Type)
-> Map TypeName Type -> Maybe Type
forall a b. (a -> b) -> a -> b
$ Manifest -> Map TypeName Type
manifestTypes Manifest
manifest of
Just (TypeArray TypeName
ctype TypeName
_ Int
_ ArrayOps
_) -> [C.cty|typename $id:(T.unpack ctype)|]
Just (TypeOpaque TypeName
ctype OpaqueOps
_ Maybe OpaqueExtraOps
_ Doc
_) -> [C.cty|typename $id:(T.unpack ctype)|]
Maybe Type
Nothing -> (Signedness -> PrimType -> Type) -> (Signedness, PrimType) -> Type
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Signedness -> PrimType -> Type
primAPIType ((Signedness, PrimType) -> Type) -> (Signedness, PrimType) -> Type
forall a b. (a -> b) -> a -> b
$ TypeName -> (Signedness, PrimType)
scalarToPrim TypeName
tname
data Kind
= Primitive
|
Array
| Record
| Sum
| Opaque
cKind :: Kind -> C.Exp
cKind :: Kind -> Exp
cKind Kind
Primitive = [C.cexp|PRIMITIVE|]
cKind Kind
Array = [C.cexp|ARRAY|]
cKind Kind
Record = [C.cexp|RECORD|]
cKind Kind
Sum = [C.cexp|SUM|]
cKind Kind
Opaque = [C.cexp|OPAQUE|]
typeBoilerplate :: Manifest -> (T.Text, Type) -> (C.Definition, C.Initializer, [C.Definition])
typeBoilerplate :: Manifest
-> (TypeName, Type) -> (Definition, Initializer, [Definition])
typeBoilerplate Manifest
manifest (TypeName
tname, TypeArray TypeName
c_type_name TypeName
et Int
rank ArrayOps
ops) =
let element_type_name :: TypeName
element_type_name = TypeName -> TypeName
typeStructName TypeName
et
element_c_type :: Type
element_c_type = Manifest -> TypeName -> Type
cType Manifest
manifest TypeName
et
type_name :: TypeName
type_name = TypeName -> TypeName
typeStructName TypeName
tname
array_name :: TypeName
array_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_array"
info_name :: TypeName
info_name = TypeName
et TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_info"
array_new_wrap :: TypeName
array_new_wrap = ArrayOps -> TypeName
arrayNew ArrayOps
ops TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
array_set_wrap :: TypeName
array_set_wrap = ArrayOps -> TypeName
arraySet ArrayOps
ops TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
array_index_wrap :: TypeName
array_index_wrap = ArrayOps -> TypeName
arrayIndex ArrayOps
ops TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
shape_args :: [Exp]
shape_args = [[C.cexp|shape[$int:i]|] | Int
i <- [Int
0 .. Int
rank Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]]
is_args :: [Exp]
is_args = [[C.cexp|is[$int:i]|] | Int
i <- [Int
0 .. Int
rank Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]]
in ( [C.cedecl|const struct type $id:type_name;|],
[C.cinit|&$id:type_name|],
[C.cunit|
int $id:array_new_wrap(struct futhark_context* ctx,
void** outp,
const void* p,
const typename int64_t* shape) {
typename $id:c_type_name *out = (typename $id:c_type_name*) outp;
*out = $id:(arrayNew ops)(ctx, p, $args:shape_args);
return 0;
}
int $id:array_set_wrap(struct futhark_context *ctx,
typename $id:c_type_name arr,
$ty:element_c_type *val,
const typename int64_t *is) {
return $id:(arraySet ops)(ctx, arr, *val, $args:is_args);
}
int $id:array_index_wrap(struct futhark_context *ctx,
void *dest,
typename $id:c_type_name arr,
const typename int64_t *is) {
return $id:(arrayIndex ops)(ctx, dest, arr, $args:is_args);
}
const struct array $id:array_name = {
.rank = $int:rank,
.element_type = &$id:element_type_name,
.info = &$id:info_name,
.name = $string:(T.unpack tname),
.num_fields = 0,
.fields = NULL,
.new = (typename array_new_fn)$id:array_new_wrap,
.set = (typename array_set_fn)$id:array_set_wrap,
.shape = (typename array_shape_fn)$id:(arrayShape ops),
.index = (typename array_index_fn)$id:array_index_wrap,
.values = (typename array_values_fn)$id:(arrayValues ops),
.free = (typename array_free_data_fn)$id:(arrayFree ops),
.zip = NULL,
};
const struct type $id:type_name = {
.name = $string:(T.unpack tname),
.restore = (typename restore_fn)restore_array,
.store = (typename store_fn)store_array,
.free = (typename free_fn)free_array,
.aux = &$id:array_name,
.kind = $exp:(cKind Array),
.info = &$id:array_name
};|]
)
typeBoilerplate Manifest
manifest (TypeName
tname, TypeOpaque TypeName
c_type_name OpaqueOps
ops Maybe OpaqueExtraOps
extra_ops Doc
_) =
let type_name :: TypeName
type_name = TypeName -> TypeName
typeStructName TypeName
tname
aux_name :: TypeName
aux_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_aux"
([Definition]
transparent_edecls, Initializer
transparent_init, Kind
kind) = TypeName
-> Maybe OpaqueExtraOps -> ([Definition], Initializer, Kind)
transparentDefs TypeName
type_name Maybe OpaqueExtraOps
extra_ops
in ( [C.cedecl|const struct type $id:type_name;|],
[C.cinit|&$id:type_name|],
[Definition]
transparent_edecls
[Definition] -> [Definition] -> [Definition]
forall a. [a] -> [a] -> [a]
++ [C.cunit|
const struct opaque_aux $id:aux_name = {
.store = (typename opaque_store_fn)$id:(opaqueStore ops),
.restore = (typename opaque_restore_fn)$id:(opaqueRestore ops),
.free = (typename opaque_free_fn)$id:(opaqueFree ops)
};
const struct type $id:type_name = {
.name = $string:(T.unpack tname),
.restore = (typename restore_fn)restore_opaque,
.store = (typename store_fn)store_opaque,
.free = (typename free_fn)free_opaque,
.aux = &$id:aux_name,
.kind = $exp:(cKind kind),
.info = $init:transparent_init
};|]
)
where
transparentDefs :: TypeName
-> Maybe OpaqueExtraOps -> ([Definition], Initializer, Kind)
transparentDefs TypeName
type_name (Just (OpaqueRecord (RecordOps [RecordField]
fields TypeName
new))) =
let new_wrap :: TypeName
new_wrap = TypeName
new TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
record_name :: TypeName
record_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_record"
fields_name :: TypeName
fields_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_fields"
onField :: Int -> RecordField -> (Initializer, BlockItem, Exp)
onField Int
i (RecordField TypeName
name TypeName
field_tname TypeName
project) =
let field_c_type :: Type
field_c_type = Manifest -> TypeName -> Type
cType Manifest
manifest TypeName
field_tname
field_v :: String
field_v = String
"v" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show (Int
i :: Int)
in ( [C.cinit|{.name = $string:(T.unpack name),
.type = &$id:(typeStructName field_tname),
.project = (typename project_fn)$id:project
}|],
[C.citem|const $ty:field_c_type $id:field_v =
*(const $ty:field_c_type*)fields[$int:i];|],
[C.cexp|$id:field_v|]
)
([Initializer]
field_inits, [BlockItem]
get_fields, [Exp]
field_args) = [(Initializer, BlockItem, Exp)]
-> ([Initializer], [BlockItem], [Exp])
forall a b c. [(a, b, c)] -> ([a], [b], [c])
unzip3 ([(Initializer, BlockItem, Exp)]
-> ([Initializer], [BlockItem], [Exp]))
-> [(Initializer, BlockItem, Exp)]
-> ([Initializer], [BlockItem], [Exp])
forall a b. (a -> b) -> a -> b
$ (Int -> RecordField -> (Initializer, BlockItem, Exp))
-> [Int] -> [RecordField] -> [(Initializer, BlockItem, Exp)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> RecordField -> (Initializer, BlockItem, Exp)
onField [Int
0 ..] [RecordField]
fields
in ( [C.cunit|
const struct field $id:fields_name[] = {
$inits:field_inits
};
int $id:new_wrap(struct futhark_context* ctx, void** outp, const void* fields[]) {
typename $id:c_type_name *out = (typename $id:c_type_name*) outp;
$items:get_fields
return $id:new(ctx, out, $args:field_args);
}
const struct record $id:record_name = {
.num_fields = $int:(length fields),
.fields = $id:fields_name,
.new = $id:new_wrap
};|],
[C.cinit|&$id:record_name|],
Kind
Record
)
transparentDefs TypeName
type_name (Just (OpaqueSum (SumOps [SumVariant]
variants TypeName
variant))) =
let sum_name :: TypeName
sum_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_sum"
variants_name :: TypeName
variants_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_variants"
onType :: Int -> TypeName -> (BlockItem, BlockItem, Exp, Initializer)
onType Int
i TypeName
type_tname =
let type_c_type :: Type
type_c_type = Manifest -> TypeName -> Type
cType Manifest
manifest TypeName
type_tname
type_v :: String
type_v = String
"v" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show (Int
i :: Int)
in ( [C.citem|const $ty:type_c_type $id:type_v =
*(const $ty:type_c_type*)types[$int:i];|],
[C.citem|$ty:type_c_type *$id:type_v =
($ty:type_c_type*)outs[$int:i];|],
[C.cexp|$id:type_v|],
[C.cinit|&$id:(typeStructName type_tname)|]
)
onVariant :: SumVariant -> (Initializer, [Definition])
onVariant (SumVariant TypeName
name [TypeName]
variant_tnames TypeName
new TypeName
destruct) =
let new_wrap :: TypeName
new_wrap = TypeName
new TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
destruct_wrap :: TypeName
destruct_wrap = TypeName
destruct TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
types_name :: TypeName
types_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_" TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_fields"
([BlockItem]
get_types, [BlockItem]
get_outs, [Exp]
type_args, [Initializer]
type_struct_names) = [(BlockItem, BlockItem, Exp, Initializer)]
-> ([BlockItem], [BlockItem], [Exp], [Initializer])
forall a b c d. [(a, b, c, d)] -> ([a], [b], [c], [d])
unzip4 ([(BlockItem, BlockItem, Exp, Initializer)]
-> ([BlockItem], [BlockItem], [Exp], [Initializer]))
-> [(BlockItem, BlockItem, Exp, Initializer)]
-> ([BlockItem], [BlockItem], [Exp], [Initializer])
forall a b. (a -> b) -> a -> b
$ (Int -> TypeName -> (BlockItem, BlockItem, Exp, Initializer))
-> [Int]
-> [TypeName]
-> [(BlockItem, BlockItem, Exp, Initializer)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> TypeName -> (BlockItem, BlockItem, Exp, Initializer)
onType [Int
0 ..] [TypeName]
variant_tnames
in ( [C.cinit|{.name = $string:(T.unpack name),
.num_types = $int:(length variant_tnames),
.types = $id:types_name,
.new = $id:new_wrap,
.destruct = $id:destruct_wrap
}|],
[C.cunit|
const struct type *$id:types_name[] = {
$inits:type_struct_names
};
int $id:new_wrap(struct futhark_context* ctx, void** outp, const void* types[]) {
typename $id:c_type_name *out = (typename $id:c_type_name*) outp;
$items:get_types
return $id:new(ctx, out, $args:type_args);
}
int $id:destruct_wrap(struct futhark_context* ctx, const void* outs[], const void* inp) {
const typename $id:c_type_name in = (const typename $id:c_type_name) inp;
$items:get_outs
return $id:destruct(ctx, $args:type_args, in);
}|]
)
([Initializer]
variant_inits, [[Definition]]
variant_wraps) = [(Initializer, [Definition])] -> ([Initializer], [[Definition]])
forall a b. [(a, b)] -> ([a], [b])
unzip ([(Initializer, [Definition])] -> ([Initializer], [[Definition]]))
-> [(Initializer, [Definition])] -> ([Initializer], [[Definition]])
forall a b. (a -> b) -> a -> b
$ (SumVariant -> (Initializer, [Definition]))
-> [SumVariant] -> [(Initializer, [Definition])]
forall a b. (a -> b) -> [a] -> [b]
map SumVariant -> (Initializer, [Definition])
onVariant [SumVariant]
variants
in ( ([Definition] -> [Definition] -> [Definition])
-> [[Definition]] -> [Definition]
forall a. (a -> a -> a) -> [a] -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 [Definition] -> [Definition] -> [Definition]
forall a. [a] -> [a] -> [a]
(++) [[Definition]]
variant_wraps
[Definition] -> [Definition] -> [Definition]
forall a. [a] -> [a] -> [a]
++ [C.cunit|
const struct variant $id:variants_name[] = {
$inits:variant_inits
};
const struct sum $id:sum_name = {
.num_variants = $int:(length variants),
.variants = $id:variants_name,
.variant = (int (*)(struct futhark_context *, const void *))$id:variant
};|],
[C.cinit|&$id:sum_name|],
Kind
Sum
)
transparentDefs TypeName
type_name (Just (OpaqueArray OpaqueArrayOps
ops')) =
TypeName
-> Int
-> TypeName
-> TypeName
-> TypeName
-> TypeName
-> TypeName
-> Maybe ([RecordField], TypeName)
-> ([Definition], Initializer, Kind)
opaqueArrayDefs
TypeName
type_name
(OpaqueArrayOps -> Int
opaqueArrayRank OpaqueArrayOps
ops')
(OpaqueArrayOps -> TypeName
opaqueArrayElemType OpaqueArrayOps
ops')
(OpaqueArrayOps -> TypeName
opaqueArrayNew OpaqueArrayOps
ops')
(OpaqueArrayOps -> TypeName
opaqueArraySet OpaqueArrayOps
ops')
(OpaqueArrayOps -> TypeName
opaqueArrayShape OpaqueArrayOps
ops')
(OpaqueArrayOps -> TypeName
opaqueArrayIndex OpaqueArrayOps
ops')
Maybe ([RecordField], TypeName)
forall a. Maybe a
Nothing
transparentDefs TypeName
type_name (Just (OpaqueRecordArray RecordArrayOps
ops')) =
TypeName
-> Int
-> TypeName
-> TypeName
-> TypeName
-> TypeName
-> TypeName
-> Maybe ([RecordField], TypeName)
-> ([Definition], Initializer, Kind)
opaqueArrayDefs
TypeName
type_name
(RecordArrayOps -> Int
recordArrayRank RecordArrayOps
ops')
(RecordArrayOps -> TypeName
recordArrayElemType RecordArrayOps
ops')
(RecordArrayOps -> TypeName
recordArrayNew RecordArrayOps
ops')
(RecordArrayOps -> TypeName
recordArraySet RecordArrayOps
ops')
(RecordArrayOps -> TypeName
recordArrayShape RecordArrayOps
ops')
(RecordArrayOps -> TypeName
recordArrayIndex RecordArrayOps
ops')
(Maybe ([RecordField], TypeName)
-> ([Definition], Initializer, Kind))
-> Maybe ([RecordField], TypeName)
-> ([Definition], Initializer, Kind)
forall a b. (a -> b) -> a -> b
$ ([RecordField], TypeName) -> Maybe ([RecordField], TypeName)
forall a. a -> Maybe a
Just (RecordArrayOps -> [RecordField]
recordArrayFields RecordArrayOps
ops', RecordArrayOps -> TypeName
recordArrayZip RecordArrayOps
ops')
transparentDefs TypeName
_ Maybe OpaqueExtraOps
_ = ([], [C.cinit|NULL|], Kind
Opaque)
opaqueArrayDefs ::
T.Text ->
Int ->
T.Text ->
CFuncName ->
CFuncName ->
CFuncName ->
CFuncName ->
Maybe ([RecordField], CFuncName) ->
([C.Definition], C.Initializer, Kind)
opaqueArrayDefs :: TypeName
-> Int
-> TypeName
-> TypeName
-> TypeName
-> TypeName
-> TypeName
-> Maybe ([RecordField], TypeName)
-> ([Definition], Initializer, Kind)
opaqueArrayDefs TypeName
type_name Int
rank TypeName
et TypeName
new TypeName
set TypeName
shape TypeName
index Maybe ([RecordField], TypeName)
maybe_fields =
let array_name :: TypeName
array_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_array"
element_type_name :: TypeName
element_type_name = TypeName -> TypeName
typeStructName TypeName
et
element_c_type :: Type
element_c_type = Manifest -> TypeName -> Type
cType Manifest
manifest TypeName
et
new_wrap :: TypeName
new_wrap = TypeName
new TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
set_wrap :: TypeName
set_wrap = TypeName
set TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
index_wrap :: TypeName
index_wrap = TypeName
index TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_wrap"
shape_args :: [Exp]
shape_args = [[C.cexp|shape[$int:i]|] | Int
i <- [Int
0 .. Int
rank Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]]
is_args :: [Exp]
is_args = [[C.cexp|is[$int:i]|] | Int
i <- [Int
0 .. Int
rank Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]]
([Definition]
zip_defs, Exp
fields_init, Int
num_fields, Exp
zip_init) =
case Maybe ([RecordField], TypeName)
maybe_fields of
Maybe ([RecordField], TypeName)
Nothing ->
( [],
[C.cexp|NULL|],
Int
0 :: Int,
[C.cexp|NULL|]
)
Just ([RecordField]
fields, TypeName
zip_f) ->
let fields_name :: TypeName
fields_name = TypeName
type_name TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_zip_fields"
zip_wrap :: TypeName
zip_wrap = TypeName
zip_f TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> TypeName
"_aux_wrap"
onField :: a -> RecordField -> (Initializer, BlockItem, Exp)
onField a
i RecordField
field =
let field_type :: Type
field_type = Manifest -> TypeName -> Type
cType Manifest
manifest (TypeName -> Type) -> TypeName -> Type
forall a b. (a -> b) -> a -> b
$ RecordField -> TypeName
recordFieldType RecordField
field
field_v :: TypeName
field_v = TypeName
"f" TypeName -> TypeName -> TypeName
forall a. Semigroup a => a -> a -> a
<> a -> TypeName
forall a. Pretty a => a -> TypeName
prettyText a
i
in ( [C.cinit|{ .name = $string:(T.unpack (recordFieldName field)),
.type = &$id:(typeStructName (recordFieldType field)),
.project = (typename project_fn)$id:(recordFieldProject field)
}|],
[C.citem|const $ty:field_type $id:field_v =
(const $ty:field_type)f[$int:i];|],
[C.cexp|$id:field_v|]
)
([Initializer]
field_inits, [BlockItem]
get_fields, [Exp]
zip_args) = [(Initializer, BlockItem, Exp)]
-> ([Initializer], [BlockItem], [Exp])
forall a b c. [(a, b, c)] -> ([a], [b], [c])
unzip3 ([(Initializer, BlockItem, Exp)]
-> ([Initializer], [BlockItem], [Exp]))
-> [(Initializer, BlockItem, Exp)]
-> ([Initializer], [BlockItem], [Exp])
forall a b. (a -> b) -> a -> b
$ (Int -> RecordField -> (Initializer, BlockItem, Exp))
-> [Int] -> [RecordField] -> [(Initializer, BlockItem, Exp)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> RecordField -> (Initializer, BlockItem, Exp)
forall {a}.
(Show a, Integral a, Pretty a) =>
a -> RecordField -> (Initializer, BlockItem, Exp)
onField [Int
0 :: Int ..] [RecordField]
fields
in ( [C.cunit|const struct field $id:fields_name[] = {
$inits:field_inits
};|]
[Definition] -> [Definition] -> [Definition]
forall a. [a] -> [a] -> [a]
++ [C.cunit|int $id:zip_wrap(struct futhark_context *ctx,
void *outp,
const void *f[]) {
typename $id:c_type_name *out = (typename $id:c_type_name*)outp;
$items:get_fields
return $id:zip_f(ctx, out, $args:zip_args);
}|],
[C.cexp|$id:fields_name|],
[RecordField] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [RecordField]
fields,
[C.cexp|(typename array_zip_fn)$id:zip_wrap|]
)
in ( [Definition]
zip_defs
[Definition] -> [Definition] -> [Definition]
forall a. [a] -> [a] -> [a]
++ [C.cunit|
int $id:new_wrap(struct futhark_context *ctx,
typename $id:c_type_name *outp,
$ty:element_c_type *ps[],
const typename int64_t shape[]) {
typename int64_t n_values = 1;
for (int i = 0; i < $int:rank; ++i) {
n_values *= shape[i];
}
$ty:element_c_type *values = alloca(n_values * sizeof($ty:element_c_type));
for (typename int64_t i = 0; i < n_values; ++i) {
values[i] = *ps[i];
}
return $id:new(ctx, outp, values, $args:shape_args);
}
int $id:set_wrap(struct futhark_context *ctx,
typename $id:c_type_name arr,
$ty:element_c_type *val,
const typename int64_t *is) {
return $id:set(ctx, arr, *val, $args:is_args);
}
int $id:index_wrap(struct futhark_context *ctx,
void *dest,
typename $id:c_type_name arr,
const typename int64_t *is) {
return $id:index(ctx, dest, arr, $args:is_args);
}
const struct array $id:array_name = {
.rank = $int:rank,
.element_type = &$id:element_type_name,
.info = NULL,
.name = $string:(T.unpack tname),
.num_fields = $int:num_fields,
.fields = $exp:fields_init,
.new = (typename array_new_fn)$id:new_wrap,
.set = (typename array_set_fn)$id:set_wrap,
.shape = (typename array_shape_fn)$id:shape,
.index = (typename array_index_fn)$id:index_wrap,
.values = NULL,
.free = NULL,
.zip = $exp:zip_init,
};|],
[C.cinit|&$id:array_name|],
Kind
Array
)
entryTypeBoilerplate :: Manifest -> ([C.Definition], [C.Initializer], [C.Definition])
entryTypeBoilerplate :: Manifest -> ([Definition], [Initializer], [Definition])
entryTypeBoilerplate Manifest
manifest =
([[Definition]] -> [Definition])
-> ([Definition], [Initializer], [[Definition]])
-> ([Definition], [Initializer], [Definition])
forall b c a.
(b -> c) -> ([Definition], a, b) -> ([Definition], a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second [[Definition]] -> [Definition]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (([Definition], [Initializer], [[Definition]])
-> ([Definition], [Initializer], [Definition]))
-> (Manifest -> ([Definition], [Initializer], [[Definition]]))
-> Manifest
-> ([Definition], [Initializer], [Definition])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Definition, Initializer, [Definition])]
-> ([Definition], [Initializer], [[Definition]])
forall a b c. [(a, b, c)] -> ([a], [b], [c])
unzip3 ([(Definition, Initializer, [Definition])]
-> ([Definition], [Initializer], [[Definition]]))
-> (Manifest -> [(Definition, Initializer, [Definition])])
-> Manifest
-> ([Definition], [Initializer], [[Definition]])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((TypeName, Type) -> (Definition, Initializer, [Definition]))
-> [(TypeName, Type)] -> [(Definition, Initializer, [Definition])]
forall a b. (a -> b) -> [a] -> [b]
map (Manifest
-> (TypeName, Type) -> (Definition, Initializer, [Definition])
typeBoilerplate Manifest
manifest) ([(TypeName, Type)] -> [(Definition, Initializer, [Definition])])
-> (Manifest -> [(TypeName, Type)])
-> Manifest
-> [(Definition, Initializer, [Definition])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map TypeName Type -> [(TypeName, Type)]
forall k a. Map k a -> [(k, a)]
M.toList (Map TypeName Type -> [(TypeName, Type)])
-> (Manifest -> Map TypeName Type)
-> Manifest
-> [(TypeName, Type)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Manifest -> Map TypeName Type
manifestTypes (Manifest -> ([Definition], [Initializer], [Definition]))
-> Manifest -> ([Definition], [Initializer], [Definition])
forall a b. (a -> b) -> a -> b
$
Manifest
manifest
oneEntryBoilerplate :: Manifest -> (T.Text, EntryPoint) -> ([C.Definition], C.Initializer)
oneEntryBoilerplate :: Manifest -> (TypeName, EntryPoint) -> ([Definition], Initializer)
oneEntryBoilerplate Manifest
manifest (TypeName
name, EntryPoint TypeName
cfun [TypeName]
tuning_params Output
output [Input]
inputs [TypeName]
attrs Doc
_doc) =
let call_f :: Name
call_f = Name
"call_" Name -> Name -> Name
forall a. Semigroup a => a -> a -> a
<> TypeName -> Name
nameFromText TypeName
name
out_type :: TypeName
out_type = Output -> TypeName
outputType Output
output
in_types :: [TypeName]
in_types = (Input -> TypeName) -> [Input] -> [TypeName]
forall a b. (a -> b) -> [a] -> [b]
map Input -> TypeName
inputType [Input]
inputs
in_types_name :: Name
in_types_name = TypeName -> Name
nameFromText TypeName
name Name -> Name -> Name
forall a. Semigroup a => a -> a -> a
<> Name
"_in_types"
in_consumed_name :: Name
in_consumed_name = TypeName -> Name
nameFromText TypeName
name Name -> Name -> Name
forall a. Semigroup a => a -> a -> a
<> Name
"_in_consumed"
tuning_params_name :: Name
tuning_params_name = TypeName -> Name
nameFromText TypeName
name Name -> Name -> Name
forall a. Semigroup a => a -> a -> a
<> Name
"_tuning_params"
attrs_name :: Name
attrs_name = TypeName -> Name
nameFromText TypeName
name Name -> Name -> Name
forall a. Semigroup a => a -> a -> a
<> Name
"_attrs"
([BlockItem]
in_items, [Exp]
in_args)
| [TypeName] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [TypeName]
in_types = ([C.citems|(void)ins;|], [Exp]
forall a. Monoid a => a
mempty)
| Bool
otherwise = [(BlockItem, Exp)] -> ([BlockItem], [Exp])
forall a b. [(a, b)] -> ([a], [b])
unzip ([(BlockItem, Exp)] -> ([BlockItem], [Exp]))
-> [(BlockItem, Exp)] -> ([BlockItem], [Exp])
forall a b. (a -> b) -> a -> b
$ (Int -> TypeName -> (BlockItem, Exp))
-> [Int] -> [TypeName] -> [(BlockItem, Exp)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> TypeName -> (BlockItem, Exp)
loadIn [Int
0 ..] [TypeName]
in_types
in ( [C.cunit|
const struct type* $id:in_types_name[] = {
$inits:(map typeStructInit in_types),
NULL
};
bool $id:in_consumed_name[] = {
$inits:(map inputUniqueInit inputs)
};
const char* $id:tuning_params_name[] = {
$inits:(map textInit tuning_params),
NULL
};
const char* $id:attrs_name[] = {
$inits:(map (textInit . prettyText) attrs),
NULL
};
int $id:call_f(struct futhark_context *ctx, void *out, void **ins) {
$items:in_items
return $id:cfun(ctx, out, $args:in_args);
}
|],
[C.cinit|{
.name = $string:(T.unpack name),
.f = $id:call_f,
.tuning_params = $id:tuning_params_name,
.in_types = $id:in_types_name,
.out_type = $init:(typeStructInit out_type),
.in_consumed = $id:in_consumed_name,
.out_fresh = $init:(outputUniqueInit output),
.attrs = $id:attrs_name
}|]
)
where
typeStructInit :: TypeName -> Initializer
typeStructInit TypeName
tname = [C.cinit|&$id:(typeStructName tname)|]
inputUniqueInit :: Input -> Initializer
inputUniqueInit = Bool -> Initializer
uniqueInit (Bool -> Initializer) -> (Input -> Bool) -> Input -> Initializer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Input -> Bool
inputConsumed
outputUniqueInit :: Output -> Initializer
outputUniqueInit = Bool -> Initializer
uniqueInit (Bool -> Initializer) -> (Output -> Bool) -> Output -> Initializer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Output -> Bool
outputFresh
uniqueInit :: Bool -> Initializer
uniqueInit Bool
True = [C.cinit|true|]
uniqueInit Bool
False = [C.cinit|false|]
loadIn :: Int -> TypeName -> (BlockItem, Exp)
loadIn Int
i TypeName
tname =
let v :: String
v = String
"in" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Int
i :: Int)
in ( [C.citem|$ty:(cType manifest tname) $id:v = *($ty:(cType manifest tname)*)ins[$int:i];|],
[C.cexp|$id:v|]
)
textInit :: TypeName -> Initializer
textInit TypeName
t = [C.cinit|$string:(T.unpack t)|]
entryBoilerplate :: Manifest -> ([C.Definition], [C.Initializer])
entryBoilerplate :: Manifest -> ([Definition], [Initializer])
entryBoilerplate Manifest
manifest =
([[Definition]] -> [Definition])
-> ([[Definition]], [Initializer]) -> ([Definition], [Initializer])
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first [[Definition]] -> [Definition]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (([[Definition]], [Initializer]) -> ([Definition], [Initializer]))
-> ([[Definition]], [Initializer]) -> ([Definition], [Initializer])
forall a b. (a -> b) -> a -> b
$
[([Definition], Initializer)] -> ([[Definition]], [Initializer])
forall a b. [(a, b)] -> ([a], [b])
unzip ([([Definition], Initializer)] -> ([[Definition]], [Initializer]))
-> [([Definition], Initializer)] -> ([[Definition]], [Initializer])
forall a b. (a -> b) -> a -> b
$
((TypeName, EntryPoint) -> ([Definition], Initializer))
-> [(TypeName, EntryPoint)] -> [([Definition], Initializer)]
forall a b. (a -> b) -> [a] -> [b]
map (Manifest -> (TypeName, EntryPoint) -> ([Definition], Initializer)
oneEntryBoilerplate Manifest
manifest) ([(TypeName, EntryPoint)] -> [([Definition], Initializer)])
-> [(TypeName, EntryPoint)] -> [([Definition], Initializer)]
forall a b. (a -> b) -> a -> b
$
Map TypeName EntryPoint -> [(TypeName, EntryPoint)]
forall k a. Map k a -> [(k, a)]
M.toList (Map TypeName EntryPoint -> [(TypeName, EntryPoint)])
-> Map TypeName EntryPoint -> [(TypeName, EntryPoint)]
forall a b. (a -> b) -> a -> b
$
Manifest -> Map TypeName EntryPoint
manifestEntryPoints Manifest
manifest
mkBoilerplate ::
Manifest ->
([C.Definition], [C.Initializer], [C.Initializer])
mkBoilerplate :: Manifest -> ([Definition], [Initializer], [Initializer])
mkBoilerplate Manifest
manifest =
let ([Definition]
type_decls, [Initializer]
type_inits, [Definition]
type_defs) = Manifest -> ([Definition], [Initializer], [Definition])
entryTypeBoilerplate Manifest
manifest
([Definition]
entry_defs, [Initializer]
entry_inits) = Manifest -> ([Definition], [Initializer])
entryBoilerplate Manifest
manifest
scalar_type_inits :: [Initializer]
scalar_type_inits = (TypeName -> Initializer) -> [TypeName] -> [Initializer]
forall a b. (a -> b) -> [a] -> [b]
map TypeName -> Initializer
scalarTypeInit [TypeName]
scalar_types
in ([Definition]
type_decls [Definition] -> [Definition] -> [Definition]
forall a. [a] -> [a] -> [a]
++ [Definition]
type_defs [Definition] -> [Definition] -> [Definition]
forall a. [a] -> [a] -> [a]
++ [Definition]
entry_defs, [Initializer]
scalar_type_inits [Initializer] -> [Initializer] -> [Initializer]
forall a. [a] -> [a] -> [a]
++ [Initializer]
type_inits, [Initializer]
entry_inits)
where
scalarTypeInit :: TypeName -> Initializer
scalarTypeInit TypeName
tname = [C.cinit|&$id:(typeStructName tname)|]
scalar_types :: [TypeName]
scalar_types =
[ TypeName
"i8",
TypeName
"i16",
TypeName
"i32",
TypeName
"i64",
TypeName
"u8",
TypeName
"u16",
TypeName
"u32",
TypeName
"u64",
TypeName
"f16",
TypeName
"f32",
TypeName
"f64",
TypeName
"bool"
]
{-# NOINLINE serverDefs #-}
serverDefs :: [Option] -> Manifest -> T.Text
serverDefs :: [Option] -> Manifest -> TypeName
serverDefs [Option]
options Manifest
manifest =
let option_parser :: Func
option_parser =
String -> [Option] -> Func
generateOptionParser String
"parse_options" ([Option] -> Func) -> [Option] -> Func
forall a b. (a -> b) -> a -> b
$ [Option]
genericOptions [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [Option]
options
([Definition]
boilerplate_defs, [Initializer]
type_inits, [Initializer]
entry_point_inits) =
Manifest -> ([Definition], [Initializer], [Initializer])
mkBoilerplate Manifest
manifest
in [Definition] -> TypeName
definitionsText
[C.cunit|
$esc:("#include <getopt.h>")
$esc:("#include <ctype.h>")
$esc:("#include <inttypes.h>")
// If the entry point is NULL, the program will terminate after doing initialisation and such. It is not used for anything else in server mode.
static const char *entry_point = "main";
$esc:(T.unpack valuesH)
$esc:(T.unpack serverH)
$esc:(T.unpack tuningH)
$edecls:boilerplate_defs
const struct type* types[] = {
$inits:type_inits,
NULL
};
struct entry_point entry_points[] = {
$inits:entry_point_inits,
{ .name = NULL }
};
struct futhark_prog prog = {
.types = types,
.entry_points = entry_points
};
$func:option_parser
int main(int argc, char** argv) {
fut_progname = argv[0];
struct futhark_context_config *cfg = futhark_context_config_new();
assert(cfg != NULL);
int parsed_options = parse_options(cfg, argc, argv);
argc -= parsed_options;
argv += parsed_options;
if (argc != 0) {
futhark_panic(1, "Excess non-option: %s\n", argv[0]);
}
struct futhark_context *ctx = futhark_context_new(cfg);
assert (ctx != NULL);
futhark_context_set_logging_file(ctx, stdout);
char* error = futhark_context_get_error(ctx);
if (error != NULL) {
futhark_panic(1, "Error during context initialisation:\n%s", error);
}
if (entry_point != NULL) {
run_server(&prog, cfg, ctx);
}
futhark_context_free(ctx);
futhark_context_config_free(cfg);
}
|]