{-# LANGUAGE QuasiQuotes #-} -- | C code generator. This module can convert a correct ImpCode -- program to an equivalent C program. The C code is strictly -- sequential, but can handle the full Futhark language. module Futhark.CodeGen.Backends.SequentialC ( compileProg , GC.CParts(..) , GC.asLibrary , GC.asExecutable ) where import Control.Monad import qualified Language.C.Quote.OpenCL as C import Futhark.IR.SeqMem import qualified Futhark.CodeGen.ImpCode.Sequential as Imp import qualified Futhark.CodeGen.ImpGen.Sequential as ImpGen import qualified Futhark.CodeGen.Backends.GenericC as GC import Futhark.MonadFreshNames -- | Compile the program to sequential C. compileProg :: MonadFreshNames m => Prog SeqMem -> m (ImpGen.Warnings, GC.CParts) compileProg = traverse (GC.compileProg "c" operations generateContext "" [DefaultSpace] []) <=< ImpGen.compileProg where operations :: GC.Operations Imp.Sequential () operations = GC.defaultOperations { GC.opsCompiler = const $ return () , GC.opsCopy = copySequentialMemory } generateContext = do cfg <- GC.publicDef "context_config" GC.InitDecl $ \s -> ([C.cedecl|struct $id:s;|], [C.cedecl|struct $id:s { int debugging; };|]) GC.publicDef_ "context_config_new" GC.InitDecl $ \s -> ([C.cedecl|struct $id:cfg* $id:s(void);|], [C.cedecl|struct $id:cfg* $id:s(void) { struct $id:cfg *cfg = (struct $id:cfg*) malloc(sizeof(struct $id:cfg)); if (cfg == NULL) { return NULL; } cfg->debugging = 0; return cfg; }|]) GC.publicDef_ "context_config_free" GC.InitDecl $ \s -> ([C.cedecl|void $id:s(struct $id:cfg* cfg);|], [C.cedecl|void $id:s(struct $id:cfg* cfg) { free(cfg); }|]) GC.publicDef_ "context_config_set_debugging" GC.InitDecl $ \s -> ([C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|], [C.cedecl|void $id:s(struct $id:cfg* cfg, int detail) { cfg->debugging = detail; }|]) GC.publicDef_ "context_config_set_logging" GC.InitDecl $ \s -> ([C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|], [C.cedecl|void $id:s(struct $id:cfg* cfg, int detail) { /* Does nothing for this backend. */ (void)cfg; (void)detail; }|]) (fields, init_fields) <- GC.contextContents ctx <- GC.publicDef "context" GC.InitDecl $ \s -> ([C.cedecl|struct $id:s;|], [C.cedecl|struct $id:s { int detail_memory; int debugging; int profiling; typename lock_t lock; char *error; int profiling_paused; $sdecls:fields };|]) GC.publicDef_ "context_new" GC.InitDecl $ \s -> ([C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg);|], [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg) { struct $id:ctx* ctx = (struct $id:ctx*) malloc(sizeof(struct $id:ctx)); if (ctx == NULL) { return NULL; } ctx->detail_memory = cfg->debugging; ctx->debugging = cfg->debugging; ctx->profiling = cfg->debugging; ctx->error = NULL; create_lock(&ctx->lock); $stms:init_fields init_constants(ctx); return ctx; }|]) GC.publicDef_ "context_free" GC.InitDecl $ \s -> ([C.cedecl|void $id:s(struct $id:ctx* ctx);|], [C.cedecl|void $id:s(struct $id:ctx* ctx) { free_constants(ctx); free_lock(&ctx->lock); free(ctx); }|]) GC.publicDef_ "context_sync" GC.MiscDecl $ \s -> ([C.cedecl|int $id:s(struct $id:ctx* ctx);|], [C.cedecl|int $id:s(struct $id:ctx* ctx) { (void)ctx; return 0; }|]) GC.publicDef_ "context_clear_caches" GC.MiscDecl $ \s -> ([C.cedecl|int $id:s(struct $id:ctx* ctx);|], [C.cedecl|int $id:s(struct $id:ctx* ctx) { (void)ctx; return 0; }|]) copySequentialMemory :: GC.Copy Imp.Sequential () copySequentialMemory destmem destidx DefaultSpace srcmem srcidx DefaultSpace nbytes = GC.copyMemoryDefaultSpace destmem destidx srcmem srcidx nbytes copySequentialMemory _ _ destspace _ _ srcspace _ = error $ "Cannot copy to " ++ show destspace ++ " from " ++ show srcspace