Talvos  0.1
SPIR-V interpreter and dynamic analysis framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Object.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018 the Talvos developers. All rights reserved.
2 //
3 // This file is distributed under a three-clause BSD license. For full license
4 // terms please see the LICENSE file distributed with this source code.
5 
8 
9 #include <cassert>
10 #include <cstring>
11 #include <iostream>
12 #include <vector>
13 
14 #include "talvos/Image.h"
15 #include "talvos/Memory.h"
16 #include "talvos/Object.h"
17 #include "talvos/Type.h"
18 
19 namespace talvos
20 {
21 
22 Object::Object(const Type *Ty, const uint8_t *Data)
23 {
24  assert(Ty);
25  this->Ty = Ty;
26  this->Data = new uint8_t[Ty->getSize()];
27  if (Data)
28  memcpy(this->Data, Data, Ty->getSize());
29 }
30 
31 template <typename T> Object::Object(const Type *Ty, T Value) : Object(Ty)
32 {
33  assert(Ty->isScalar());
34  assert(sizeof(T) == Ty->getSize());
35  *((T *)Data) = Value;
36 }
37 
38 Object::~Object() { delete[] Data; }
39 
41 {
42  Data = nullptr;
43  if (Src)
44  {
45  Ty = Src.Ty;
46  Data = new uint8_t[Ty->getSize()];
47  memcpy(Data, Src.Data, Ty->getSize());
50  }
51 }
52 
54 {
55  if (this != &Src)
56  {
57  Object Tmp(Src);
58  std::swap(Data, Tmp.Data);
59  std::swap(Ty, Tmp.Ty);
60  std::swap(MatrixLayout, Tmp.MatrixLayout);
61  std::swap(DescriptorElements, Tmp.DescriptorElements);
62  }
63  return *this;
64 }
65 
66 Object::Object(Object &&Src) noexcept
67 {
68  Ty = Src.Ty;
69  Data = Src.Data;
70  MatrixLayout = Src.MatrixLayout;
71  DescriptorElements = Src.DescriptorElements;
72  Src.Data = nullptr;
73 }
74 
75 Object Object::extract(const std::vector<uint32_t> &Indices) const
76 {
77  assert(Data);
78 
79  // Loop over indices to compute byte offset and result type.
80  size_t Offset = 0;
81  const Type *Ty = this->Ty;
82  for (size_t i = 0; i < Indices.size(); i++)
83  {
84  assert(Ty->isComposite());
85  Offset += Ty->getElementOffset(Indices[i]);
86  Ty = Ty->getElementType(Indices[i]);
87  }
88 
89  // Create result object and copy data over.
90  Object Result;
91  Result.Ty = Ty;
92  Result.Data = new uint8_t[Ty->getSize()];
93  memcpy(Result.Data, Data + Offset, Ty->getSize());
94  return Result;
95 }
96 
97 template <typename T> T Object::get(uint32_t Element) const
98 {
99  assert(Data);
100  assert(Ty->isScalar() || Ty->isVector());
101  assert(Ty->isScalar() ? (sizeof(T) == Ty->getSize() && Element == 0)
102  : sizeof(T) == Ty->getElementType()->getSize());
103  return ((T *)Data)[Element];
104 }
105 
107 {
108  return DescriptorElements;
109 }
110 
112 {
113  assert(Ty->isPointer() && (Ty->getElementType()->isVector() ||
114  Ty->getElementType()->isMatrix()));
115  return MatrixLayout;
116 }
117 
118 void Object::insert(const std::vector<uint32_t> &Indices, const Object &Element)
119 {
120  assert(Data);
121 
122  // Loop over indices to compute byte offset.
123  size_t Offset = 0;
124  const Type *Ty = this->Ty;
125  for (size_t i = 0; i < Indices.size(); i++)
126  {
127  assert(Ty->isComposite());
128  Offset += Ty->getElementOffset(Indices[i]);
129  Ty = Ty->getElementType(Indices[i]);
130  }
131 
132  // Copy element data.
133  assert(Ty->getSize() == Element.Ty->getSize());
134  memcpy(Data + Offset, Element.Data, Ty->getSize());
135 }
136 
137 Object Object::load(const Type *Ty, const Memory &Mem, uint64_t Address)
138 {
139  Object Result;
140  Result.Ty = Ty;
141  Result.Data = new uint8_t[Ty->getSize()];
142  Mem.load(Result.Data, Address, Ty->getSize());
143  return Result;
144 }
145 
146 Object Object::load(const Type *Ty, const Memory &Mem, const Object &Pointer)
147 {
148  Object Result;
149  Result.Ty = Ty;
150  Result.Data = new uint8_t[Ty->getSize()];
151 
152  // Special case for loading matrices from memory with non-default layouts.
153  if (Pointer.MatrixLayout)
154  {
155  assert(Ty->getTypeId() == Type::VECTOR || Ty->getTypeId() == Type::MATRIX);
156 
157  const Type *VecTy = Ty->isMatrix() ? Ty->getElementType() : Ty;
158  const Type *ElemTy = VecTy->getElementType();
159 
160  // Loop over columns (vectors).
161  uint32_t NumCols = Ty->isMatrix() ? Ty->getElementCount() : 1;
162  for (uint32_t Col = 0; Col < NumCols; Col++)
163  {
164  // Calculate offsets into source and destination pointers.
165  uint8_t *DstPtr = Result.Data + Ty->getElementOffset(Col);
166  uint64_t SrcPtr = Pointer.get<uint64_t>();
168  SrcPtr += Col * Pointer.MatrixLayout.Stride;
169  else
170  SrcPtr += Col * ElemTy->getSize();
171 
172  // Loop over elements in column and load them to result object.
173  for (uint32_t Row = 0; Row < VecTy->getElementCount(); Row++)
174  {
175  Mem.load(DstPtr, SrcPtr, ElemTy->getSize());
176 
177  // Increment pointers.
178  DstPtr += ElemTy->getSize();
180  SrcPtr += ElemTy->getSize();
181  else
182  SrcPtr += Pointer.MatrixLayout.Stride;
183  }
184  }
185  }
186  else
187  {
188  Mem.load(Result.Data, Pointer.get<uint64_t>(), Ty->getSize());
189  }
190 
191  return Result;
192 }
193 
196 void print(std::ostream &Stream, uint8_t *Data, const Type *Ty)
197 {
198  switch (Ty->getTypeId())
199  {
200  case Type::BOOL:
201  {
202  Stream << (*(bool *)Data ? "true" : "false");
203  break;
204  }
205  case Type::INT:
206  {
207  Stream << std::dec;
208  switch (Ty->getBitWidth())
209  {
210  case 16:
211  Stream << *(int16_t *)Data;
212  break;
213  case 32:
214  Stream << *(int32_t *)Data;
215  break;
216  case 64:
217  Stream << *(int64_t *)Data;
218  break;
219  default:
220  assert(false && "Invalid integer type.");
221  }
222  break;
223  }
224  case Type::FLOAT:
225  {
226  switch (Ty->getBitWidth())
227  {
228  case 32:
229  Stream << *(float *)Data;
230  break;
231  case 64:
232  Stream << *(double *)Data;
233  break;
234  default:
235  assert(false && "Invalid floating point type.");
236  }
237  break;
238  }
239  case Type::ARRAY:
240  case Type::STRUCT:
241  case Type::VECTOR:
242  case Type::MATRIX:
243  {
244  Stream << "{";
245  for (unsigned i = 0; i < Ty->getElementCount(); i++)
246  {
247  if (i > 0)
248  Stream << ", ";
249  print(Stream, Data + Ty->getElementOffset(i), Ty->getElementType(i));
250  }
251  Stream << "}";
252  break;
253  }
254  case Type::IMAGE:
255  {
256  ImageView *Image = *(ImageView **)Data;
257  Stream << Ty << std::endl;
258  Stream << std::endl;
259  Stream << Image->getWidth() << " x " << Image->getHeight() << " x "
260  << Image->getDepth() << std::endl;
261  Stream << Image->getNumArrayLayers() << " layers" << std::endl;
262  Stream << Image->getNumMipLevels() << " mip levels" << std::endl;
263  Stream << "Format = " << Image->getFormat() << std::endl;
264  break;
265  }
266  case Type::SAMPLER:
267  {
268  // TODO: Show information about the sampler.
269  Stream << "sampler object";
270  break;
271  }
272  case Type::POINTER:
273  {
274  Stream << "0x" << std::hex << *(uint64_t *)Data << std::dec;
275  break;
276  }
277  default:
278  Stream << "<unhandled object type>";
279  break;
280  }
281 }
282 
283 std::ostream &operator<<(std::ostream &Stream, const Object &O)
284 {
285  if (!O)
286  {
287  Stream << "<undefined>";
288  return Stream;
289  }
290 
291  print(Stream, O.Data, O.getType());
292  return Stream;
293 }
294 
295 template <typename T> void Object::set(T Value, uint32_t Element)
296 {
297  assert(Data);
298  assert(Ty->isScalar() || Ty->isVector());
299  assert(Ty->isScalar() ? (sizeof(T) == Ty->getSize() && Element == 0)
300  : sizeof(T) == Ty->getElementType()->getSize());
301  ((T *)Data)[Element] = Value;
302 }
303 
305 {
306  assert(Ty->isPointer() && Ty->getElementType()->isArray());
307  DescriptorElements = DAE;
308 }
309 
311 {
312  assert(Ty->isPointer() && (Ty->getElementType()->isVector() ||
313  Ty->getElementType()->isMatrix()));
314  MatrixLayout = ML;
315 }
316 
317 void Object::store(Memory &Mem, uint64_t Address) const
318 {
319  assert(Data);
320  Mem.store(Address, Ty->getSize(), Data);
321 }
322 
323 void Object::store(Memory &Mem, const Object &Pointer) const
324 {
325  assert(Data);
326 
327  // Special case for loading matrices from memory with non-default layouts.
328  if (Pointer.MatrixLayout)
329  {
330  assert(Ty->getTypeId() == Type::VECTOR || Ty->getTypeId() == Type::MATRIX);
331 
332  const Type *VecTy = Ty->isMatrix() ? Ty->getElementType() : Ty;
333  const Type *ElemTy = VecTy->getElementType();
334 
335  // Loop over columns (vectors).
336  uint32_t NumCols = Ty->isMatrix() ? Ty->getElementCount() : 1;
337  for (uint32_t Col = 0; Col < NumCols; Col++)
338  {
339  // Calculate offsets into source and destination pointers.
340  uint8_t *SrcPtr = Data + Ty->getElementOffset(Col);
341  uint64_t DstPtr = Pointer.get<uint64_t>();
343  DstPtr += Col * Pointer.MatrixLayout.Stride;
344  else
345  DstPtr += Col * ElemTy->getSize();
346 
347  // Loop over elements in column and load them to result object.
348  for (uint32_t Row = 0; Row < VecTy->getElementCount(); Row++)
349  {
350  Mem.store(DstPtr, ElemTy->getSize(), SrcPtr);
351 
352  // Increment pointers.
353  SrcPtr += ElemTy->getSize();
355  DstPtr += ElemTy->getSize();
356  else
357  DstPtr += Pointer.MatrixLayout.Stride;
358  }
359  }
360  }
361  else
362  {
363  Mem.store(Pointer.get<uint64_t>(), Ty->getSize(), Data);
364  }
365 }
366 
367 void Object::zero() { memset(Data, 0, Ty->getSize()); }
368 
369 // Explicit template instantiations for scalar types.
371 #define INSTANTIATE(TYPE) \
372  template Object::Object(const talvos::Type *Ty, TYPE Value); \
373  template TYPE Object::get(uint32_t) const; \
374  template void Object::set(TYPE, uint32_t)
375 INSTANTIATE(bool);
376 INSTANTIATE(int8_t);
377 INSTANTIATE(int16_t);
378 INSTANTIATE(int32_t);
379 INSTANTIATE(int64_t);
380 INSTANTIATE(uint8_t);
381 INSTANTIATE(uint16_t);
382 INSTANTIATE(uint32_t);
383 INSTANTIATE(uint64_t);
384 INSTANTIATE(float);
385 INSTANTIATE(double);
387 
388 } // namespace talvos
const DescriptorElement * getDescriptorElements() const
Returns the descriptor array element information.
Definition: Object.cpp:106
bool isScalar() const
Returns true if this is a scalar type.
Definition: Type.cpp:77
~Object()
Destroy this object.
Definition: Object.cpp:38
This class represents an image object.
Definition: Image.h:24
void setDescriptorElements(const DescriptorElement *DAE)
Set the descriptor array elements for this object.
Definition: Object.cpp:304
size_t getSize() const
Returns the size of this type in bytes.
Definition: Type.h:81
INSTANTIATE(bool)
Structure to describe the memory layout of a matrix.
Definition: Object.h:24
bool isPointer() const
Returns true if this is a pointer type.
Definition: Type.h:116
size_t getElementOffset(uint64_t Index) const
Returns the byte offset of the element at Index.
Definition: Type.cpp:26
const Type * getElementType(uint64_t Index=0) const
Returns the type of the element at Index.
Definition: Type.cpp:38
This class represents a view into a range of image subresources.
Definition: Image.h:178
void store(Memory &Mem, uint64_t Address) const
Store the value of this object to memory at Address.
Definition: Object.cpp:317
bool isArray() const
Returns true if this is an array type.
Definition: Type.h:95
bool isMatrix() const
Returns true if this is a matrix type.
Definition: Type.h:113
void set(T Value, uint32_t Element=0)
Set the value of this object to a scalar of type T.
Definition: Object.cpp:295
uint32_t getElementCount() const
Returns the number of elements in this array, struct, or vector type.
Definition: Type.h:64
VkFormat getFormat() const
Returns the format of the image.
Definition: Image.h:195
uint32_t getNumArrayLayers() const
Returns the number of array layers in the image view.
Definition: Image.h:204
static Object load(const Type *Ty, const Memory &Mem, uint64_t Address)
Create an object of type Ty from the data at Address.
Definition: Object.cpp:137
uint32_t getWidth(uint32_t Level=0) const
Get the width of the image view at the specified mip level.
Definition: Image.cpp:482
This file declares the Type class.
enum talvos::PtrMatrixLayout::@4 Order
Specifies the order of the elements in memory.
const DescriptorElement * DescriptorElements
Descriptor array element information.
Definition: Object.h:151
bool isComposite() const
Returns true if this is an array, struct, or vector type.
Definition: Type.cpp:72
uint32_t Stride
The stride in bytes between columns (COL_MAJOR) or rows (ROW_MAJOR).
Definition: Object.h:35
This class represents an address space in the virtual device.
Definition: Memory.h:37
uint32_t getDepth(uint32_t Level=0) const
Get the depth of the image view at the specified mip level.
Definition: Image.cpp:465
uint8_t * Data
The raw data backing this object.
Definition: Object.h:143
Structure used to hold information about an element of a descriptor array.
Definition: Object.h:42
This file declares data structures and functions for handling images.
PtrMatrixLayout MatrixLayout
The memory layout of a matrix that this object points to.
Definition: Object.h:147
uint32_t getBitWidth() const
Returns the bit-width of this type.
Definition: Type.cpp:20
void zero()
Set all of the value bits in this object to zero.
Definition: Object.cpp:367
This file declares the Object class.
void setMatrixLayout(const PtrMatrixLayout &ML)
Set the matrix layout for this object.
Definition: Object.cpp:310
Object()
Create an empty, uninitialized object.
Definition: Object.h:55
std::ostream & operator<<(std::ostream &Stream, const Dim3 &D)
Definition: Dim3.cpp:16
const Type * getType() const
Returns the type of this object.
Definition: Object.h:101
uint32_t getHeight(uint32_t Level=0) const
Get the height of the image view at the specified mip level.
Definition: Image.cpp:470
This file declares the Memory class.
Object & operator=(const Object &Src)
Copy-assign to this object, cloning the data from Src.
Definition: Object.cpp:53
TypeId getTypeId() const
Returns the type ID of this type.
Definition: Type.h:92
void load(uint8_t *Result, uint64_t Address, uint64_t NumBytes) const
Load NumBytes of data from Address into Result.
Definition: Memory.cpp:249
const PtrMatrixLayout & getMatrixLayout() const
Get the matrix layout for this object.
Definition: Object.cpp:111
This class represents a SPIR-V type.
Definition: Type.h:33
void insert(const std::vector< uint32_t > &Indices, const Object &Element)
Insert the value of Element into a composite object.
Definition: Object.cpp:118
This class represents an instruction result.
Definition: Object.h:51
void store(uint64_t Address, uint64_t NumBytes, const uint8_t *Data)
Store NumBytes of data from Data to Address.
Definition: Memory.cpp:306
T get(uint32_t Element=0) const
Get the value of this object as a scalar of type T.
Definition: Object.cpp:97
uint32_t getNumMipLevels() const
Returns the number of mip levels in the image view.
Definition: Image.h:207
bool isVector() const
Returns true if this is a vector type.
Definition: Type.h:125
Object extract(const std::vector< uint32_t > &Indices) const
Extract an element from a composite object.
Definition: Object.cpp:75
const Type * Ty
The type of this object.
Definition: Object.h:142
void print(std::ostream &Stream, uint8_t *Data, const Type *Ty)
Recursively print typed data to a stream.
Definition: Object.cpp:196