Merge topic 'fix-nightly-gcc5-cuda'

0182eb9d9 Test variant arguments to worklets
de28a4351 Add an entry to VariantUnion to help compiler copy structs

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3030
This commit is contained in:
Kenneth Moreland 2023-04-19 21:30:18 +00:00 committed by Kitware Robot
commit 2f75729cd7
4 changed files with 469 additions and 4 deletions

@ -0,0 +1,70 @@
# Fixed issue with trivial variant copies
A rare error occurred with trivial copies of variants. The problem is likely
a compiler bug, and has so far only been observed when passing the variant
to a CUDA kernel when compiling with GCC 5.
The problem was caused by structures with padding. `struct` objects in
C/C++ are frequently padded with unused memory to align all entries
properly. For example, consider the following simple `struct`.
``` cpp
struct FooHasPadding
{
vtkm::Int32 A;
// Padding here.
vtkm::Int64 C;
};
```
Because the `C` member is a 64-bit integer, it needs to be aligned on
8-byte (i.e., 64-bit) address locations. For this to work, the C++ compiler
adds 4 bytes of padding between `A` and `C` so that an array of
`FooHasPadding`s will have the `C` member always on an 8-byte boundary.
Now consider a second `struct` that is similar to the first but has a valid
member where the padding would be.
``` cpp
struct BarNoPadding
{
vtkm::Int32 A;
vtkm::Int32 B;
vtkm::Int64 C;
};
```
This structure does not need padding because the `A` and `B` members
combine to fill the 8 bytes that `C` needs for the alignment. Both
`FooHasPadding` and `BarNoPadding` fill 16 bytes of memory. The `A` and `C`
members are at the same offsets, respectively, for the two structures. The
`B` member happens to reside just where the padding is for `FooHasPadding`.
Now, let's say we create a `vtkm::exec::Variant<FooHasPadding, BarNoPadding>`.
Internally, the `Variant` class holds a union that looks roughly like the
following.
``` cpp
union VariantUnion
{
FooHasPadding V0;
BarNoPadding V1;
};
```
This is a perfectly valid use of a `union`. We just need to keep track of
which type of object is in it (which the `Variant` object does for you).
The problem appeared to occur when `VariantUnion` contained a
`BarNoPadding` and was passed from the host to the device via an argument
to a global function. The compiler must notice that the first type
(`FooHasPadding`) is the "biggest" and uses that for trivial copies (which
just copy bytes like `memcpy`). Since it's using `FooHasPadding` as its
prototype for the byte copy, and accidentally skips over padded regions that
are valid when the `union` contains a `BarNoPadding`. This appears to be a
compiler bug. (At least, I cannot find a reason why this is encroaching
undefined behavior.)
The solution adds a new, unused type to the internal `union` for `Variant`
that is an object as large as the largest entry in the union and contains
no padding.

@ -24,6 +24,7 @@
#include <vtkmstd/is_trivial.h>
#include <algorithm>
#include <type_traits>
@ -51,6 +52,58 @@ template <typename... Ts>
using AllTriviallyDestructible =
vtkm::ListAll<vtkm::List<Ts...>, vtkmstd::is_trivially_destructible>;
// --------------------------------------------------------------------------------
// Helper functions to determine the maximum type size.
#if defined(VTKM_GCC) && (__GNUC__ == 5)
// GCC5 gives an error with `sizeof(Ts)...` for an unexpanded parameter pack.
template <typename T0>
constexpr std::size_t MaxSizeOf()
{
return sizeof(T0);
}
template <typename T0, typename T1, typename... Ts>
constexpr std::size_t MaxSizeOf()
{
return std::max(sizeof(T0), MaxSizeOf<T1, Ts...>());
}
#else
template <typename... Ts>
constexpr std::size_t MaxSizeOf()
{
return std::max({ sizeof(Ts)... });
}
#endif
// --------------------------------------------------------------------------------
// Placeholder for a fully used structure of the given type.
template <std::size_t Size, bool = (Size > 8)>
struct SizedPlaceholder
{
VTKM_STATIC_ASSERT(Size > 0);
vtkm::Int8 A;
SizedPlaceholder<Size - 1> B;
};
template <>
struct SizedPlaceholder<1, false>
{
vtkm::Int8 A;
};
template <std::size_t Size>
struct SizedPlaceholder<Size, true>
{
vtkm::Int8 A;
vtkm::Int8 B;
vtkm::Int8 C;
vtkm::Int8 D;
vtkm::Int8 E;
vtkm::Int8 F;
vtkm::Int8 G;
vtkm::Int8 H;
SizedPlaceholder<Size - 8> I;
};
// clang-format off
// --------------------------------------------------------------------------------
@ -94,6 +147,11 @@ union VariantUnionNTD;
template <typename T0>
union VariantUnionTD<T0>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0>()> Placeholder;
T0 V0;
VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
VariantUnionTD() = default;
@ -101,6 +159,11 @@ union VariantUnionTD<T0>
template <typename T0>
union VariantUnionNTD<T0>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0>()> Placeholder;
T0 V0;
VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
VariantUnionNTD() = default;
@ -110,6 +173,11 @@ union VariantUnionNTD<T0>
template <typename T0, typename T1>
union VariantUnionTD<T0, T1>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1>()> Placeholder;
T0 V0;
T1 V1;
VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
@ -118,6 +186,11 @@ union VariantUnionTD<T0, T1>
template <typename T0, typename T1>
union VariantUnionNTD<T0, T1>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1>()> Placeholder;
T0 V0;
T1 V1;
VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
@ -128,6 +201,11 @@ union VariantUnionNTD<T0, T1>
template <typename T0, typename T1, typename T2>
union VariantUnionTD<T0, T1, T2>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -137,6 +215,11 @@ union VariantUnionTD<T0, T1, T2>
template <typename T0, typename T1, typename T2>
union VariantUnionNTD<T0, T1, T2>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -148,6 +231,11 @@ union VariantUnionNTD<T0, T1, T2>
template <typename T0, typename T1, typename T2, typename T3>
union VariantUnionTD<T0, T1, T2, T3>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -158,6 +246,11 @@ union VariantUnionTD<T0, T1, T2, T3>
template <typename T0, typename T1, typename T2, typename T3>
union VariantUnionNTD<T0, T1, T2, T3>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -170,6 +263,11 @@ union VariantUnionNTD<T0, T1, T2, T3>
template <typename T0, typename T1, typename T2, typename T3, typename T4>
union VariantUnionTD<T0, T1, T2, T3, T4>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -181,6 +279,11 @@ union VariantUnionTD<T0, T1, T2, T3, T4>
template <typename T0, typename T1, typename T2, typename T3, typename T4>
union VariantUnionNTD<T0, T1, T2, T3, T4>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -194,6 +297,11 @@ union VariantUnionNTD<T0, T1, T2, T3, T4>
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
union VariantUnionTD<T0, T1, T2, T3, T4, T5>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4, T5>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -206,6 +314,11 @@ union VariantUnionTD<T0, T1, T2, T3, T4, T5>
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
union VariantUnionNTD<T0, T1, T2, T3, T4, T5>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4, T5>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -220,6 +333,11 @@ union VariantUnionNTD<T0, T1, T2, T3, T4, T5>
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4, T5, T6>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -233,6 +351,11 @@ union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6>
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4, T5, T6>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -248,6 +371,11 @@ union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6>
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6, T7>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4, T5, T6, T7>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -262,6 +390,11 @@ union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6, T7>
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6, T7>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4, T5, T6, T7>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -279,6 +412,11 @@ union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6, T7>
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename... Ts>
union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;
@ -296,6 +434,11 @@ union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename... Ts>
union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>()> Placeholder;
T0 V0;
T1 V1;
T2 V2;

@ -36,6 +36,7 @@ $# Ignore the following comment. It is meant for the generated file.
#include <vtkmstd/is_trivial.h>
#include <algorithm>
#include <type_traits>
$py(max_expanded=8)\
@ -84,6 +85,58 @@ template <typename... Ts>
using AllTriviallyDestructible =
vtkm::ListAll<vtkm::List<Ts...>, vtkmstd::is_trivially_destructible>;
// --------------------------------------------------------------------------------
// Helper functions to determine the maximum type size.
#if defined(VTKM_GCC) && (__GNUC__ == 5)
// GCC5 gives an error with `sizeof(Ts)...` for an unexpanded parameter pack.
template <typename T0>
constexpr std::size_t MaxSizeOf()
{
return sizeof(T0);
}
template <typename T0, typename T1, typename... Ts>
constexpr std::size_t MaxSizeOf()
{
return std::max(sizeof(T0), MaxSizeOf<T1, Ts...>());
}
#else
template <typename... Ts>
constexpr std::size_t MaxSizeOf()
{
return std::max({ sizeof(Ts)... });
}
#endif
// --------------------------------------------------------------------------------
// Placeholder for a fully used structure of the given type.
template <std::size_t Size, bool = (Size > 8)>
struct SizedPlaceholder
{
VTKM_STATIC_ASSERT(Size > 0);
vtkm::Int8 A;
SizedPlaceholder<Size - 1> B;
};
template <>
struct SizedPlaceholder<1, false>
{
vtkm::Int8 A;
};
template <std::size_t Size>
struct SizedPlaceholder<Size, true>
{
vtkm::Int8 A;
vtkm::Int8 B;
vtkm::Int8 C;
vtkm::Int8 D;
vtkm::Int8 E;
vtkm::Int8 F;
vtkm::Int8 G;
vtkm::Int8 H;
SizedPlaceholder<Size - 8> I;
};
// clang-format off
// --------------------------------------------------------------------------------
@ -128,6 +181,11 @@ $for(param_length in range(max_expanded))\
template <$typename_list(param_length)>
union VariantUnionTD<$type_list(param_length)>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<$type_list(param_length)>()> Placeholder;
$for(param_index in range(param_length + 1))\
T$(param_index) V$(param_index);
$endfor\
@ -137,6 +195,11 @@ $endfor\
template <$typename_list(param_length)>
union VariantUnionNTD<$type_list(param_length)>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<$type_list(param_length)>()> Placeholder;
$for(param_index in range(param_length + 1))\
T$(param_index) V$(param_index);
$endfor\
@ -150,6 +213,11 @@ $endfor\
template <$typename_list(max_expanded), typename... Ts>
union VariantUnionTD<$type_list(max_expanded), Ts...>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<$type_list(max_expanded), Ts...>()> Placeholder;
$for(param_index in range(max_expanded))\
T$(param_index) V$(param_index);
$endfor\
@ -162,6 +230,11 @@ $endfor\
template <$typename_list(max_expanded), typename... Ts>
union VariantUnionNTD<$type_list(max_expanded), Ts...>
{
// Work around issue where CUDA sometimes seems to miss initializing some struct members
// if another entry in the varient has a struct with padding. Place an item that requires
// everthing to be copied.
SizedPlaceholder<MaxSizeOf<$type_list(max_expanded), Ts...>()> Placeholder;
$for(param_index in range(max_expanded))\
T$(param_index) V$(param_index);
$endfor\

@ -10,13 +10,19 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ExecutionObjectBase.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/UncertainArrayHandle.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/Variant.h>
#include <vtkm/cont/testing/Testing.h>
namespace map_exec_field
{
struct SimpleExecObject : vtkm::cont::ExecutionObjectBase
{
template <typename Device>
@ -55,9 +61,6 @@ struct TestExecObjectWorklet
};
};
namespace map_exec_field
{
static constexpr vtkm::Id ARRAY_SIZE = 10;
template <typename WorkletType>
@ -105,6 +108,179 @@ struct DoTestWorklet
}
};
struct StructWithPadding
{
vtkm::Int32 A;
// Padding here
vtkm::Int64 C;
};
struct StructWithoutPadding
{
vtkm::Int32 A;
vtkm::Int32 B;
vtkm::Int64 C;
};
struct LargerStruct
{
vtkm::Int64 C;
vtkm::Int64 D;
vtkm::Int64 E;
};
using VariantTypePadding = vtkm::exec::Variant<StructWithPadding, StructWithoutPadding>;
using VariantTypeSizes = vtkm::exec::Variant<StructWithPadding, StructWithoutPadding, LargerStruct>;
struct VarientPaddingExecObj : vtkm::cont::ExecutionObjectBase
{
VariantTypePadding Variant;
VTKM_CONT VariantTypePadding PrepareForExecution(const vtkm::cont::DeviceAdapterId&,
vtkm::cont::Token&) const
{
return this->Variant;
}
};
struct VarientSizesExecObj : vtkm::cont::ExecutionObjectBase
{
VariantTypeSizes Variant;
VTKM_CONT VariantTypeSizes PrepareForExecution(const vtkm::cont::DeviceAdapterId&,
vtkm::cont::Token&) const
{
return this->Variant;
}
};
struct TestVariantExecObjectPadding : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldOut a, FieldOut c, ExecObject varient);
// Using an output field as the domain is weird, but it works.
using InputDomain = _1;
VTKM_EXEC void operator()(vtkm::Int32& a, vtkm::Int64& c, const VariantTypePadding& variant) const
{
a = variant.Get<StructWithPadding>().A;
c = variant.Get<StructWithPadding>().C;
}
};
struct TestVariantExecObjectNoPadding : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldOut a, FieldOut b, FieldOut c, ExecObject varient);
// Using an output field as the domain is weird, but it works.
using InputDomain = _1;
VTKM_EXEC void operator()(vtkm::Int32& a,
vtkm::Int32& b,
vtkm::Int64& c,
const VariantTypePadding& variant) const
{
a = variant.Get<StructWithoutPadding>().A;
b = variant.Get<StructWithoutPadding>().B;
c = variant.Get<StructWithoutPadding>().C;
}
};
struct TestVariantExecObjectLarger : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldOut c, FieldOut d, FieldOut e, ExecObject varient);
// Using an output field as the domain is weird, but it works.
using InputDomain = _1;
VTKM_EXEC void operator()(vtkm::Int64& c,
vtkm::Int64& d,
vtkm::Int64& e,
const VariantTypeSizes& variant) const
{
c = variant.Get<LargerStruct>().C;
d = variant.Get<LargerStruct>().D;
e = variant.Get<LargerStruct>().E;
}
};
void DoTestVariant()
{
vtkm::cont::ArrayHandle<vtkm::Int32> a;
vtkm::cont::ArrayHandle<vtkm::Int32> b;
vtkm::cont::ArrayHandle<vtkm::Int64> c;
vtkm::cont::ArrayHandle<vtkm::Int64> d;
vtkm::cont::ArrayHandle<vtkm::Int64> e;
// Usually you don't need to allocate output arrays, but these worklets do a
// weird thing of using an output array as the input domain (because the
// generative worklets have no input). It's weird to use an output field as
// the input domain, but it works as long as you preallocate the data.
a.Allocate(ARRAY_SIZE);
b.Allocate(ARRAY_SIZE);
c.Allocate(ARRAY_SIZE);
d.Allocate(ARRAY_SIZE);
e.Allocate(ARRAY_SIZE);
vtkm::cont::Invoker invoke;
std::cout << "Struct with Padding" << std::endl;
{
VarientPaddingExecObj execObject;
execObject.Variant =
StructWithPadding{ TestValue(0, vtkm::Int32{}), TestValue(1, vtkm::Int64{}) };
invoke(TestVariantExecObjectPadding{}, a, c, execObject);
auto aPortal = a.ReadPortal();
auto cPortal = c.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(aPortal.Get(index) == TestValue(0, vtkm::Int32{}));
VTKM_TEST_ASSERT(cPortal.Get(index) == TestValue(1, vtkm::Int64{}));
}
}
std::cout << "Struct without Padding" << std::endl;
{
VarientPaddingExecObj execObject;
execObject.Variant = StructWithoutPadding{ TestValue(2, vtkm::Int32{}),
TestValue(3, vtkm::Int32{}),
TestValue(4, vtkm::Int64{}) };
invoke(TestVariantExecObjectNoPadding{}, a, b, c, execObject);
auto aPortal = a.ReadPortal();
auto bPortal = b.ReadPortal();
auto cPortal = c.ReadPortal();
// An odd bug was observed with some specific compilers. (Specifically, this was
// last observed with GCC5 used with nvcc compiling CUDA code for the Pascal
// architecture.) It concerned a Variant that contained 2 or more objects of the
// same `sizeof` and the first one listed had some padding (to satisfy alignment)
// and the second one did not. Internally, the `Variant` object constructs a
// `union` of types in the order listed. The compiler seemed to recognize that the
// first entry in the union was the "largest" and used that for trivial copies.
// However, it also recognized the padding in that first object and skipped
// copying that value even if the union was set to the second object. If that
// condition is happening, you will probably see a failure when testing the
// bPortal below.
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(aPortal.Get(index) == TestValue(2, vtkm::Int32{}));
VTKM_TEST_ASSERT(bPortal.Get(index) == TestValue(3, vtkm::Int32{}));
VTKM_TEST_ASSERT(cPortal.Get(index) == TestValue(4, vtkm::Int64{}));
}
}
std::cout << "LargerStruct" << std::endl;
{
VarientSizesExecObj execObject;
execObject.Variant = LargerStruct{ TestValue(5, vtkm::Int64{}),
TestValue(6, vtkm::Int64{}),
TestValue(7, vtkm::Int64{}) };
invoke(TestVariantExecObjectLarger{}, c, d, e, execObject);
auto cPortal = c.ReadPortal();
auto dPortal = d.ReadPortal();
auto ePortal = e.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(cPortal.Get(index) == TestValue(5, vtkm::Int64{}));
VTKM_TEST_ASSERT(dPortal.Get(index) == TestValue(6, vtkm::Int64{}));
VTKM_TEST_ASSERT(ePortal.Get(index) == TestValue(7, vtkm::Int64{}));
}
}
}
void TestWorkletMapFieldExecArg(vtkm::cont::DeviceAdapterId id)
{
std::cout << "Testing Worklet with WholeArray on device adapter: " << id.GetName() << std::endl;
@ -112,9 +288,12 @@ void TestWorkletMapFieldExecArg(vtkm::cont::DeviceAdapterId id)
std::cout << "--- Worklet accepting all types." << std::endl;
vtkm::testing::Testing::TryTypes(map_exec_field::DoTestWorklet<TestExecObjectWorklet>(),
vtkm::TypeListCommon());
std::cout << "--- Worklet passing variant." << std::endl;
DoTestVariant();
}
} // anonymous namespace
} // anonymous-ish namespace
int UnitTestWorkletMapFieldExecArg(int argc, char* argv[])
{