Commit Graph

8 Commits

Author SHA1 Message Date
Kenneth Moreland
6ccb32d27b Slight comment changes 2021-03-31 14:35:06 -06:00
Kenneth Moreland
647bc94fed Reduce the number of lines required to implement Variant::CastAndCall 2021-03-31 09:49:40 -06:00
Kenneth Moreland
991eeba9f3 Reduce the number of lines required to implement VariantUnion 2021-03-30 14:35:44 -06:00
Kenneth Moreland
7607736ef4 Reduce the number of lines required to implement AllTrivially* 2021-03-30 14:05:53 -06:00
Kenneth Moreland
cb60401a63 Use specialized class instead of function overload for Variant::Get
Nvcc was having troubles resolving the return type of the overloaded
function to get a value out of a `VariantUnion`. Replace the
implementation with a class with specializations. This is more verbose,
but easier on the compiler.
2021-03-30 10:16:16 -06:00
Kenneth Moreland
c9bcdd0195 Use a union in Variant for safe type punning
Create a `VaraintUnion` that is an actual C++ `union` to store the data
in a `Variant`.

You may be asking yourself, why not just use an `std::aligned_union`
rather than a real union type? That was our first implementation, but
the problem is that the `std::aligned_union` reference needs to be
recast to the actual type. Typically you would do that with
`reinterpret_cast`. However, doing that leads to undefined behavior. The
C++ compiler assumes that 2 pointers of different types point to
different memory (even if it is clear that they are set to the same
address). That means optimizers can remove code because it "knows" that
data in one type cannot affect data in another type. To safely change
the type of an `std::aligned_union`, you really have to do an
`std::memcpy`. This is problematic for types that cannot be trivially
copied. Another problem is that we found that device compilers do not
optimize the memcpy as well as most CPU compilers. Likely, memcpy is
used much less frequently on GPU devices.
2021-03-30 10:16:16 -06:00
Kenneth Moreland
e3dfa48910 Do not attempt to move non-trivial objects in Variant
The `Variant` class has separate implementations for its move and copy
constructors/assignment operators depending on whether the classes it
holds can be trivially moved. If the objects are trivial, Variant is
trivial as well. However, in the case where the objects are not trivial,
special construction and copying needs to be done.

Previously, the non-trivial `Variant` defined a move constructor that
did a byte copy of the contained object and reset the right hand side
object so that it did not attempt to destroy the object. That usually
works because it guarantees that only one version of the `Variant` will
attempt to destroy the object and its resources should be cleaned up
correctly.

But C++ is a funny language that lets you do weird things. Turns out
there are cases where moving the location of memory for an object
without calling the proper copy method can invalidate the object. For
example, if the object holds a pointer to one of its own members, that
pointer will become invalid. Also, if it points to something that points
back, then the object will need to update those pointers when it is
moved. GCC's version of `std::string` seems to be a type like this.

Solve the problem by simply deleting the move constructors. The copy
constructors and destructor will be called instead to properly manage
the object. A test for these conditions is added to `UnitTestVariant`.
2020-11-09 12:48:10 -07:00
Kenneth Moreland
21db210a73 Make separate exec and cont versions of Variant
The `Variant` class is templated to hold objects of other types.
Depending on whether those objects of are meant to be used in the
control or execution side, the methods on `Variant` might need to be
declared with (or without) special modifiers. We can sometimes try to
compile the `Variant` methods for both host and device and ask the
device compiler to ignore incompatibilities, but that does not always
work.

To get around that, create two different implementations of `Variant`.
Their API and implementation is exactly the same except one declares its
methods with `VTKM_CONT` and the other its methods `VTKM_EXEC`.
2020-11-09 12:48:10 -07:00