Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Construction and destruction of sum values in C API. #2086

Merged
merged 1 commit into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Trailing commas are now allowed for all syntactical elements that
involve comma-separation. (#2068)

* The C API now allows destruction and construction of sum types (with
some caveats). (#2074)

### Removed

### Changed
Expand Down
2 changes: 1 addition & 1 deletion cabal.project
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
packages: futhark.cabal
index-state: 2024-01-03T21:19:52Z
index-state: 2024-01-14T18:48:23Z

package futhark
ghc-options: -j -fwrite-ide-info -hiedir=.hie
55 changes: 55 additions & 0 deletions docs/c-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,61 @@ types.
The resulting value *aliases* the record, but has its own lifetime,
and must eventually be freed.

.. _sums:

Sums
~~~~

A sum type is an opaque type (see above) that supports construction
and destruction functions. An opaque type is a sum type if its
definition is a sum type at the Futhark level.

Similarly to records (see :ref:`Records`), this functionality is
equivalent to writing entry points by hand, and have the same
properties regarding lifetimes.

A sum type consists of one or more variants. A value of this type is
always an instance of one of these variants. In the C API, these
variants are numbered from zero. The numbering is given by the order
in which they are represented in the manifest (see :ref:`manifest`),
which is also the order in which their associated functions are
defined in the header file.

For an opaque sum type ``t``, the following function is always
generated.

.. c:function:: int futhark_variant_opaque_t(struct futhark_context *ctx, const struct futhark_opaque_t *v);

Return the identifying number of the variant of which this sum type
is an instance (see above). Cannot fail.

For each variant ``foo``, construction and destruction functions are
defined. The following assume ``t`` is defined as ``type t = #foo
([]i32) bool``.

.. c:function:: int futhark_new_opaque_t_foo(struct futhark_context *ctx, struct futhark_opaque_contrived **out, const struct futhark_i32_1d *v0, const bool v1);

Construct a value of type ``t`` that is an instance of the variant
``foo``. Arguments are provided in the same order as in the
Futhark-level ``foo`` constructr.

**Beware:** if ``t`` has size parameters that are only used for
*other* variants than the one that is being instantiated, those
size parameters will be set to 0. If this is a problem for your
application, define your own entry point for constructing a value
with the proper sizes.

.. c:function:: int futhark_destruct_opaque_contrived_foo(struct futhark_context *ctx, struct futhark_i32_1d **v0, bool *v1, const struct futhark_opaque_contrived *obj);

Extract the payload of variant ``foo`` from the sum value. Despite
the name, "destruction" does not free the sum type value. The
extracted values alias the sum value, but has their own lifetime,
and must eventually be freed.

**Precondition:** ``t`` must be an instance of the ``foo`` variant,
which can be determined with :c:func:`futhark_variant_opaque_t`.


Entry points
------------

Expand Down
22 changes: 22 additions & 0 deletions docs/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,28 @@
}
},
"additionalProperties": false
},
"sum": {
"type": "object",
"properties": {
"variant": {"type": "string"},
"variants": {
"type": "array",
"items": {
"type": "object",
"properties": {
"construct": {"type": "string"},
"destruct": {"type": "string"},
"payload": {"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"additionalProperties": false
}
},
"required": [ "kind", "ctype", "ops" ]
Expand Down
2 changes: 1 addition & 1 deletion futhark.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ library
, free >=5.1.10
, futhark-data >= 1.1.0.0
, futhark-server >= 1.2.2.1
, futhark-manifest >= 1.2.0.1
, futhark-manifest >= 1.3.0.0
, githash >=0.1.6.1
, half >= 0.3
, haskeline
Expand Down
4 changes: 2 additions & 2 deletions nix/futhark-manifest.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
}:
mkDerivation {
pname = "futhark-manifest";
version = "1.2.0.1";
sha256 = "Bj5E84pvspyONfQZ7rYJWu1y1GnXuWaHdAgtj1IZS58=";
version = "1.3.0.0";
sha256 = "778996f0086e35fe0c36fd2dd66cc6db0704053845ba44cfcee0d5d4c2a4df54";
libraryHaskellDepends = [ aeson base bytestring containers text ];
testHaskellDepends = [
base QuickCheck quickcheck-instances tasty tasty-hunit
Expand Down
6 changes: 3 additions & 3 deletions src/Futhark/CodeGen/Backends/GenericC/CLI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ readInput manifest i tname =
[C.cstm|;|],
[C.cexp|$id:dest|]
)
Just (TypeOpaque desc _ _) ->
Just (TypeOpaque desc _ _ _) ->
( [C.citems|futhark_panic(1, "Cannot read input #%d of type %s\n", $int:i, $string:(T.unpack desc));|],
[C.cstm|;|],
[C.cstm|;|],
Expand Down Expand Up @@ -256,7 +256,7 @@ prepareOutputs manifest = zipWith prepareResult [(0 :: Int) ..]
[C.cexp|$id:result|],
[C.cstm|assert($id:(arrayFree ops)(ctx, $id:result) == 0);|]
)
Just (TypeOpaque t ops _) ->
Just (TypeOpaque t ops _ _) ->
( [C.citem|typename $id:t $id:result;|],
[C.cexp|$id:result|],
[C.cstm|assert($id:(opaqueFree ops)(ctx, $id:result) == 0);|]
Expand All @@ -269,7 +269,7 @@ printStm manifest tname e =
Nothing ->
let info = tname <> "_info"
in [C.cstm|write_scalar(stdout, binary_output, &$id:info, &$exp:e);|]
Just (TypeOpaque desc _ _) ->
Just (TypeOpaque desc _ _ _) ->
[C.cstm|{
fprintf(stderr, "Values of type \"%s\" have no external representation.\n", $string:(T.unpack desc));
retval = 1;
Expand Down
4 changes: 2 additions & 2 deletions src/Futhark/CodeGen/Backends/GenericC/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ cType :: Manifest -> TypeName -> C.Type
cType manifest tname =
case M.lookup tname $ manifestTypes manifest of
Just (TypeArray ctype _ _ _) -> [C.cty|typename $id:(T.unpack ctype)|]
Just (TypeOpaque ctype _ _) -> [C.cty|typename $id:(T.unpack ctype)|]
Just (TypeOpaque ctype _ _ _) -> [C.cty|typename $id:(T.unpack ctype)|]
Nothing -> uncurry primAPIType $ scalarToPrim tname

-- First component is forward declaration so we don't have to worry
Expand Down Expand Up @@ -156,7 +156,7 @@ typeBoilerplate _ (tname, TypeArray _ et rank ops) =
.aux = &$id:aux_name
};|]
)
typeBoilerplate manifest (tname, TypeOpaque c_type_name ops record) =
typeBoilerplate manifest (tname, TypeOpaque c_type_name ops record _sumops) =
let type_name = typeStructName tname
aux_name = type_name <> "_aux"
(record_edecls, record_init) = recordDefs type_name record
Expand Down
Loading