blob: f8ec2e79f4a5934f84081272e62aa2007eba0a9a [file] [log] [blame]
Shih-wei Liao462aefd2010-06-04 15:32:04 -07001#include <vector>
2
3#include "slang_rs_context.hpp"
4#include "slang_rs_export_type.hpp"
5#include "slang_rs_export_element.hpp"
6
7#include "llvm/Type.h"
8#include "llvm/DerivedTypes.h"
9
10#include "llvm/ADT/StringExtras.h" /* for function llvm::utostr_32() */
11#include "llvm/Target/TargetData.h" /* for class llvm::TargetData and class llvm::StructLayout */
12
13namespace slang {
14
15/****************************** RSExportType ******************************/
16bool RSExportType::NormalizeType(const Type*& T, llvm::StringRef& TypeName) {
17 llvm::SmallPtrSet<const Type*, 8> SPS = llvm::SmallPtrSet<const Type*, 8>();
18
19 if((T = RSExportType::TypeExportable(T, SPS)) == NULL)
20 /* TODO: warning the user: type not exportable */
21 return false;
22
23 /* Get type name */
24 TypeName = RSExportType::GetTypeName(T);
25 if(TypeName.empty())
26 /* TODO: warning the user: the type is unnmaed */
27 return false;
28
29 return true;
30}
31
32const Type* RSExportType::GetTypeOfDecl(const DeclaratorDecl* DD) {
33 if(DD && DD->getTypeSourceInfo()) {
34 QualType T = DD->getTypeSourceInfo()->getType();
35 if(T.isNull())
36 return NULL;
37 else
38 return T.getTypePtr();
39 }
40}
41
42llvm::StringRef RSExportType::GetTypeName(const Type* T) {
43 T = GET_CANONICAL_TYPE(T);
44 if(T == NULL)
45 return llvm::StringRef();
46
47 switch(T->getTypeClass()) {
48 case Type::Builtin:
49 {
50 const BuiltinType* BT = UNSAFE_CAST_TYPE(BuiltinType, T);
51
52 switch(BT->getKind()) {
53#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \
54 case builtin_type: \
55 /* Compiler is smart enough to optimize following *big if branches* since they all become "constant comparison" after macro expansion */ \
56 if(type == RSExportPrimitiveType::DataTypeFloat32) return "float"; \
57 else if(type == RSExportPrimitiveType::DataTypeUnsigned8) return "uchar"; \
58 else if(type == RSExportPrimitiveType::DataTypeUnsigned16) return "ushort"; \
59 else if(type == RSExportPrimitiveType::DataTypeUnsigned32) return "uint"; \
60 else if(type == RSExportPrimitiveType::DataTypeSigned8) return "char"; \
61 else if(type == RSExportPrimitiveType::DataTypeSigned16) return "short"; \
62 else if(type == RSExportPrimitiveType::DataTypeSigned32) return "int"; \
63 else assert(false && "Unknow data type of supported builtin"); \
64 break;
65#include "slang_rs_export_type_support.inc"
66
67 default: assert(false && "Unknow data type of the builtin"); break;
68 }
69 }
70 break;
71
72 case Type::Record:
73 {
74 const RecordDecl* RD = T->getAsStructureType()->getDecl();
75 llvm::StringRef Name = RD->getName();
76 if(Name.empty()) {
77 if(RD->getTypedefForAnonDecl() != NULL)
78 Name = RD->getTypedefForAnonDecl()->getName();
79
80 if(Name.empty())
81 /* Try to find a name from redeclaration (i.e. typedef) */
82 for(TagDecl::redecl_iterator RI = RD->redecls_begin();
83 RI != RD->redecls_end();
84 RI++)
85 {
86 assert(*RI != NULL && "cannot be NULL object");
87
88 Name = (*RI)->getName();
89 if(!Name.empty())
90 break;
91 }
92 }
93 return Name;
94 }
95 break;
96
97 case Type::Pointer:
98 {
99 /* "*" plus pointee name */
100 const Type* PT = GET_POINTEE_TYPE(T);
101 llvm::StringRef PointeeName;
102 if(NormalizeType(PT, PointeeName)) {
103 char* Name = new char[ 1 /* * */ + PointeeName.size() ];
104 Name[0] = '*';
105 memcpy(Name + 1, PointeeName.data(), PointeeName.size());
106 return Name;
107 }
108 }
109 break;
110
111 case Type::ExtVector:
112 {
113 const ExtVectorType* EVT = UNSAFE_CAST_TYPE(ExtVectorType, T);
114 return RSExportVectorType::GetTypeName(EVT);
115 }
116 break;
117
118 default:
119 break;
120 }
121
122 return llvm::StringRef();
123}
124
125const Type* RSExportType::TypeExportable(const Type* T, llvm::SmallPtrSet<const Type*, 8>& SPS) {
126 /* Normailize first */
127 if((T = GET_CANONICAL_TYPE(T)) == NULL)
128 return NULL;
129
130 if(SPS.count(T))
131 return T;
132
133 switch(T->getTypeClass()) {
134 case Type::Builtin:
135 {
136 const BuiltinType* BT = UNSAFE_CAST_TYPE(BuiltinType, T);
137
138 switch(BT->getKind()) {
139#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \
140 case builtin_type:
141#include "slang_rs_export_type_support.inc"
142 return T;
143 break;
144
145 default:
146 return NULL;
147 break;
148 }
149 }
150 break;
151
152 case Type::Record:
153 {
154 if(RSExportPrimitiveType::GetRSObjectType(T) != RSExportPrimitiveType::DataTypeUnknown)
155 return T; /* RS object type, no further checks are needed */
156
157 /* Check internal struct */
158 const RecordDecl* RD = T->getAsStructureType()->getDecl();
159 if(RD != NULL)
160 RD = RD->getDefinition();
161
162 /* Fast check */
163 if(RD->hasFlexibleArrayMember() || RD->hasObjectMember())
164 return NULL;
165
166 /* Insert myself into checking set */
167 SPS.insert(T);
168
169 /* Check all element */
170 for(RecordDecl::field_iterator F = RD->field_begin();
171 F != RD->field_end();
172 F++)
173 {
174 const Type* FT = GetTypeOfDecl(*F);
175 FT = GET_CANONICAL_TYPE(FT);
176
177 if(!TypeExportable(FT, SPS))
178 /* TODO: warning: unsupported field type */
179 return NULL;
180 }
181
182 return T;
183 }
184 break;
185
186 case Type::Pointer:
187 {
188 const PointerType* PT = UNSAFE_CAST_TYPE(PointerType, T);
189 const Type* PointeeType = GET_POINTEE_TYPE(PT);
190
191 if((PointeeType->getTypeClass() != Type::Pointer) && (TypeExportable(PointeeType, SPS) == NULL) )
192 return NULL;
193 return T;
194 }
195 break;
196
197 case Type::ExtVector:
198 {
199 const ExtVectorType* EVT = UNSAFE_CAST_TYPE(ExtVectorType, T);
200 /* Check element numbers */
201 if(EVT->getNumElements() < 2 || EVT->getNumElements() > 4) /* only support vector with size 2, 3 and 4 */
202 return NULL;
203
204 /* Check base element type */
205 const Type* ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
206
207 if((ElementType->getTypeClass() != Type::Builtin) || (TypeExportable(ElementType, SPS) == NULL))
208 return NULL;
209 return T;
210 }
211 break;
212
213 default:
214 return NULL;
215 break;
216 }
217}
218
219RSExportType* RSExportType::Create(RSContext* Context, const Type* T, const llvm::StringRef& TypeName) {
220 /*
221 * Lookup the context to see whether the type was processed before.
222 * Newly create RSExportType will insert into context in RSExportType::RSExportType()
223 */
224 RSContext::export_type_iterator ETI = Context->findExportType(TypeName);
225
226 if(ETI != Context->export_types_end())
227 return ETI->second;
228
229 RSExportType* ET = NULL;
230 switch(T->getTypeClass()) {
231 case Type::Record:
232 if(RSExportPrimitiveType::GetRSObjectType(TypeName) != RSExportPrimitiveType::DataTypeUnknown)
233 ET = RSExportPrimitiveType::Create(Context, T, TypeName);
234 else
235 ET = RSExportRecordType::Create(Context, T->getAsStructureType(), TypeName);
236 break;
237
238 case Type::Builtin:
239 ET = RSExportPrimitiveType::Create(Context, T, TypeName);
240 break;
241
242 case Type::Pointer:
243 ET = RSExportPointerType::Create(Context, UNSAFE_CAST_TYPE(PointerType, T), TypeName);
244 /* free the name (allocated in RSExportType::GetTypeName) */
245 delete [] TypeName.data();
246 break;
247
248 case Type::ExtVector:
249 ET = RSExportVectorType::Create(Context, UNSAFE_CAST_TYPE(ExtVectorType, T), TypeName);
250 break;
251
252 default:
253 /* TODO: warning: type is not exportable */
254 printf("RSExportType::Create : type '%s' is not exportable\n", T->getTypeClassName());
255 break;
256 }
257
258 return ET;
259}
260
261RSExportType* RSExportType::Create(RSContext* Context, const Type* T) {
262 llvm::StringRef TypeName;
263 if(NormalizeType(T, TypeName))
264 return Create(Context, T, TypeName);
265 else
266 return NULL;
267}
268
269RSExportType* RSExportType::CreateFromDecl(RSContext* Context, const VarDecl* VD) {
270 return RSExportType::Create(Context, GetTypeOfDecl(VD));
271}
272
273size_t RSExportType::GetTypeStoreSize(const RSExportType* ET) {
274 return ET->getRSContext()->getTargetData()->getTypeStoreSize(ET->getLLVMType());
275}
276
277size_t RSExportType::GetTypeAllocSize(const RSExportType* ET) {
278 return ET->getRSContext()->getTargetData()->getTypeAllocSize(ET->getLLVMType());
279}
280
281RSExportType::RSExportType(RSContext* Context, const llvm::StringRef& Name) :
282 mContext(Context),
283 mName(Name.data(), Name.size()), /* make a copy on Name since data of @Name which is stored in ASTContext will be destroyed later */
284 mLLVMType(NULL)
285{
286 /* TODO: need to check whether the insertion is successful or not */
287 Context->insertExportType(Name, this);
288 return;
289}
290
291/****************************** RSExportPrimitiveType ******************************/
292RSExportPrimitiveType::RSObjectTypeMapTy* RSExportPrimitiveType::RSObjectTypeMap = NULL;
293llvm::Type* RSExportPrimitiveType::RSObjectLLVMType = NULL;
294
295bool RSExportPrimitiveType::IsPrimitiveType(const Type* T) {
296 if((T != NULL) && (T->getTypeClass() == Type::Builtin))
297 return true;
298 else
299 return false;
300}
301
302RSExportPrimitiveType::DataType RSExportPrimitiveType::GetRSObjectType(const llvm::StringRef& TypeName) {
303 if(TypeName.empty())
304 return DataTypeUnknown;
305
306 if(RSObjectTypeMap == NULL) {
307 RSObjectTypeMap = new RSObjectTypeMapTy(16);
308
309#define USE_ELEMENT_DATA_TYPE
310#define DEF_RS_OBJECT_TYPE(type, name) \
311 RSObjectTypeMap->GetOrCreateValue(name, GET_ELEMENT_DATA_TYPE(type));
312#include "slang_rs_export_element_support.inc"
313 }
314
315 RSObjectTypeMapTy::const_iterator I = RSObjectTypeMap->find(TypeName);
316 if(I == RSObjectTypeMap->end())
317 return DataTypeUnknown;
318 else
319 return I->getValue();
320}
321
322RSExportPrimitiveType::DataType RSExportPrimitiveType::GetRSObjectType(const Type* T) {
323 T = GET_CANONICAL_TYPE(T);
324 if((T == NULL) || (T->getTypeClass() != Type::Record))
325 return DataTypeUnknown;
326
327 return GetRSObjectType( RSExportType::GetTypeName(T) );
328}
329
330const size_t RSExportPrimitiveType::SizeOfDataTypeInBytes[RSExportPrimitiveType::DataTypeMax + 1] = {
331 0,
332 2, /* DataTypeFloat16 */
333 4, /* DataTypeFloat32 */
334 8, /* DataTypeFloat64 */
335 1, /* DataTypeSigned8 */
336 2, /* DataTypeSigned16 */
337 4, /* DataTypeSigned32 */
338 8, /* DataTypeSigned64 */
339 1, /* DataTypeUnsigned8 */
340 2, /* DataTypeUnsigned16 */
341 4, /* DataTypeUnsigned32 */
342 8, /* DataTypeUnSigned64 */
343
344 2, /* DataTypeUnsigned565 */
345 2, /* DataTypeUnsigned5551 */
346 2, /* DataTypeUnsigned4444 */
347
348 4, /* DataTypeRSElement */
349 4, /* DataTypeRSType */
350 4, /* DataTypeRSAllocation */
351 4, /* DataTypeRSSampler */
352 4, /* DataTypeRSScript */
353 4, /* DataTypeRSMesh */
354 4, /* DataTypeRSProgramFragment */
355 4, /* DataTypeRSProgramVertex */
356 4, /* DataTypeRSProgramRaster */
357 4, /* DataTypeRSProgramStore */
358 0
359};
360
361size_t RSExportPrimitiveType::GetSizeInBytes(const RSExportPrimitiveType* EPT) {
362 assert(((EPT->getType() >= DataTypeFloat32) && (EPT->getType() < DataTypeMax)) && "RSExportPrimitiveType::GetSizeInBytes : unknown data type");
363 return SizeOfDataTypeInBytes[ static_cast<int>(EPT->getType()) ];
364}
365
366RSExportPrimitiveType::DataType RSExportPrimitiveType::GetDataType(const Type* T) {
367 if(T == NULL)
368 return DataTypeUnknown;
369
370 switch(T->getTypeClass()) {
371 case Type::Builtin:
372 {
373 const BuiltinType* BT = UNSAFE_CAST_TYPE(BuiltinType, T);
374 switch(BT->getKind()) {
375#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \
376 case builtin_type: \
377 return type; \
378 break;
379#include "slang_rs_export_type_support.inc"
380
381 /* The size of types Long, ULong and WChar depend on platform so we abandon the support to them */
382 /* Type of its size exceeds 32 bits (e.g. int64_t, double, etc.) does not support */
383
384 default:
385 /* TODO: warning the user: unsupported type */
386 printf("RSExportPrimitiveType::GetDataType : built-in type has no corresponding data type for built-in type");
387 break;
388 }
389 }
390 break;
391
392 case Type::Record:
393 /* must be RS object type */
394 return RSExportPrimitiveType::GetRSObjectType(T);
395 break;
396
397 default:
398 printf("RSExportPrimitiveType::GetDataType : type '%s' is not supported primitive type", T->getTypeClassName());
399 break;
400 }
401
402 return DataTypeUnknown;
403}
404
405RSExportPrimitiveType* RSExportPrimitiveType::Create(RSContext* Context, const Type* T, const llvm::StringRef& TypeName, DataKind DK, bool Normalized) {
406 DataType DT = GetDataType(T);
407
408 if((DT == DataTypeUnknown) || TypeName.empty())
409 return NULL;
410 else
411 return new RSExportPrimitiveType(Context, TypeName, DT, DK, Normalized);
412}
413
414RSExportPrimitiveType* RSExportPrimitiveType::Create(RSContext* Context, const Type* T, DataKind DK) {
415 llvm::StringRef TypeName;
416 if(RSExportType::NormalizeType(T, TypeName) && IsPrimitiveType(T))
417 return Create(Context, T, TypeName, DK);
418 else
419 return NULL;
420}
421
422RSExportType::ExportClass RSExportPrimitiveType::getClass() const {
423 return RSExportType::ExportClassPrimitive;
424}
425
426const llvm::Type* RSExportPrimitiveType::convertToLLVMType() const {
427 llvm::LLVMContext& C = getRSContext()->getLLVMContext();
428
429 if(isRSObjectType()) {
430 /* struct { int* p; } __attribute__((packed, aligned(pointer_size))) which is <{ [1 x i32] }> in LLVM */
431 if(RSObjectLLVMType == NULL) {
432 std::vector<const llvm::Type*> Elements;
433 Elements.push_back( llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1) );
434 RSObjectLLVMType = llvm::StructType::get(C, Elements, true);
435 }
436 return RSObjectLLVMType;
437 }
438
439 switch(mType) {
440 case DataTypeFloat32:
441 return llvm::Type::getFloatTy(C);
442 break;
443
444 case DataTypeSigned8:
445 case DataTypeUnsigned8:
446 return llvm::Type::getInt8Ty(C);
447 break;
448
449 case DataTypeSigned16:
450 case DataTypeUnsigned16:
451 case DataTypeUnsigned565:
452 case DataTypeUnsigned5551:
453 case DataTypeUnsigned4444:
454 return llvm::Type::getInt16Ty(C);
455 break;
456
457 case DataTypeSigned32:
458 case DataTypeUnsigned32:
459 return llvm::Type::getInt32Ty(C);
460 break;
461
462 default:
463 assert(false && "Unknown data type");
464 break;
465 }
466
467 return NULL;
468}
469
470/****************************** RSExportPointerType ******************************/
471
472const Type* RSExportPointerType::IntegerType = NULL;
473
474RSExportPointerType* RSExportPointerType::Create(RSContext* Context, const PointerType* PT, const llvm::StringRef& TypeName) {
475 const Type* PointeeType = GET_POINTEE_TYPE(PT);
476 const RSExportType* PointeeET;
477
478 if(PointeeType->getTypeClass() != Type::Pointer) {
479 PointeeET = RSExportType::Create(Context, PointeeType);
480 } else {
481 /* Double or higher dimension of pointer, export as int* */
482 assert(IntegerType != NULL && "Built-in integer type is not set");
483 PointeeET = RSExportPrimitiveType::Create(Context, IntegerType);
484 }
485
486 if(PointeeET == NULL) {
487 printf("Failed to create type for pointee");
488 return NULL;
489 }
490
491 return new RSExportPointerType(Context, TypeName, PointeeET);
492}
493
494RSExportType::ExportClass RSExportPointerType::getClass() const {
495 return RSExportType::ExportClassPointer;
496}
497
498const llvm::Type* RSExportPointerType::convertToLLVMType() const {
499 const llvm::Type* PointeeType = mPointeeType->getLLVMType();
500 return llvm::PointerType::getUnqual(PointeeType);
501}
502
503/****************************** RSExportVectorType ******************************/
504const char* RSExportVectorType::VectorTypeNameStore[][3] = {
505 /* 0 */ { "char2", "char3", "char4" },
506 /* 1 */ { "uchar2", "uchar3", "uchar4" },
507 /* 2 */ { "short2", "short3", "short4" },
508 /* 3 */ { "ushort2", "ushort3", "ushort4" },
509 /* 4 */ { "int2", "int3", "int4" },
510 /* 5 */ { "uint2", "uint3", "uint4" },
511 /* 6 */ { "float2", "float3", "float4" },
512};
513
514llvm::StringRef RSExportVectorType::GetTypeName(const ExtVectorType* EVT) {
515 const Type* ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
516
517 if((ElementType->getTypeClass() != Type::Builtin))
518 return llvm::StringRef();
519
520 const BuiltinType* BT = UNSAFE_CAST_TYPE(BuiltinType, ElementType);
521 const char** BaseElement = NULL;
522
523 switch(BT->getKind()) {
524#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \
525 case builtin_type: \
526 /* Compiler is smart enough to optimize following *big if branches* since they all become "constant comparison" after macro expansion */ \
527 if(type == RSExportPrimitiveType::DataTypeSigned8) BaseElement = VectorTypeNameStore[0]; \
528 else if(type == RSExportPrimitiveType::DataTypeUnsigned8) BaseElement = VectorTypeNameStore[1]; \
529 else if(type == RSExportPrimitiveType::DataTypeSigned16) BaseElement = VectorTypeNameStore[2]; \
530 else if(type == RSExportPrimitiveType::DataTypeUnsigned16) BaseElement = VectorTypeNameStore[3]; \
531 else if(type == RSExportPrimitiveType::DataTypeSigned32) BaseElement = VectorTypeNameStore[4]; \
532 else if(type == RSExportPrimitiveType::DataTypeUnsigned32) BaseElement = VectorTypeNameStore[5]; \
533 else if(type == RSExportPrimitiveType::DataTypeFloat32) BaseElement = VectorTypeNameStore[6]; \
534 break;
535#include "slang_rs_export_type_support.inc"
536
537 default: return llvm::StringRef(); break;
538 }
539
540 if((BaseElement != NULL) && (EVT->getNumElements() > 1) && (EVT->getNumElements() <= 4))
541 return BaseElement[EVT->getNumElements() - 2];
542 else
543 return llvm::StringRef();
544}
545
546RSExportVectorType* RSExportVectorType::Create(RSContext* Context, const ExtVectorType* EVT, const llvm::StringRef& TypeName, DataKind DK, bool Normalized) {
547 assert(EVT != NULL && EVT->getTypeClass() == Type::ExtVector);
548
549 const Type* ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
550 RSExportPrimitiveType::DataType DT = RSExportPrimitiveType::GetDataType(ElementType);
551
552 if(DT != RSExportPrimitiveType::DataTypeUnknown)
553 return new RSExportVectorType(Context, TypeName, DT, DK, Normalized, EVT->getNumElements());
554 else
555 printf("RSExportVectorType::Create : unsupported base element type\n");
556}
557
558RSExportType::ExportClass RSExportVectorType::getClass() const {
559 return RSExportType::ExportClassVector;
560}
561
562const llvm::Type* RSExportVectorType::convertToLLVMType() const {
563 const llvm::Type* ElementType = RSExportPrimitiveType::convertToLLVMType();
564 return llvm::VectorType::get(ElementType, getNumElement());
565}
566
567/****************************** RSExportRecordType ******************************/
568RSExportRecordType* RSExportRecordType::Create(RSContext* Context, const RecordType* RT, const llvm::StringRef& TypeName, bool mIsArtificial) {
569 assert(RT != NULL && RT->getTypeClass() == Type::Record);
570
571 const RecordDecl* RD = RT->getDecl();
572 assert(RD->isStruct());
573
574 RD = RD->getDefinition();
575 if(RD == NULL) {
576 /* TODO: warning: actual struct definition isn't declared in this moudle */
577 printf("RSExportRecordType::Create : this struct is not defined in this module.");
578 return NULL;
579 }
580
581 RSExportRecordType* ERT = new RSExportRecordType(Context, TypeName, RD->hasAttr<PackedAttr>(), mIsArtificial);
582 unsigned int Index = 0;
583
584 for(RecordDecl::field_iterator fit = RD->field_begin();
585 fit != RD->field_end();
586 fit++, Index++)
587 {
588#define FAILED_CREATE_FIELD(err) do { \
589 if(*err) \
590 printf("RSExportRecordType::Create : failed to create field (%s)\n", err); \
591 delete ERT; \
592 return NULL; \
593 } while(false)
594 /* FIXME: All fields should be primitive type */
595 assert((*fit)->getKind() == Decl::Field);
596 FieldDecl* FD = *fit;
597
598 /* We don't support bit field TODO: allow bitfield with size 8, 16, 32 */
599 if(FD->isBitField())
600 FAILED_CREATE_FIELD("bit field is not supported");
601
602 /* Type */
603 RSExportType* ET = RSExportElement::CreateFromDecl(Context, FD);
604
605 if(ET != NULL)
606 ERT->mFields.push_back( new Field(ET, FD->getName(), ERT, Index) );
607 else
608 FAILED_CREATE_FIELD(FD->getName().str().c_str());
609#undef FAILED_CREATE_FIELD
610 }
611
612 return ERT;
613}
614
615RSExportType::ExportClass RSExportRecordType::getClass() const {
616 return RSExportType::ExportClassRecord;
617}
618
619const llvm::Type* RSExportRecordType::convertToLLVMType() const {
620 std::vector<const llvm::Type*> FieldTypes;
621
622 for(const_field_iterator FI = fields_begin();
623 FI != fields_end();
624 FI++)
625 {
626 const Field* F = *FI;
627 const RSExportType* FET = F->getType();
628
629 FieldTypes.push_back(FET->getLLVMType());
630 }
631
632 return llvm::StructType::get(getRSContext()->getLLVMContext(), FieldTypes, mIsPacked);
633}
634
635/****************************** RSExportRecordType::Field ******************************/
636size_t RSExportRecordType::Field::getOffsetInParent() const {
637 /* Struct layout obtains below will be cached by LLVM */
638 const llvm::StructLayout* SL = mParent->getRSContext()->getTargetData()->getStructLayout(static_cast<const llvm::StructType*>(mParent->getLLVMType()));
639 return SL->getElementOffset(mIndex);
640}
641
642} /* namespace slang */