1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
#pragma once
#include "Size.h"
#include "Reference.h"
#include "Core/Array.h"
#include "Core/GcArray.h"
#include "Core/Object.h"
#include "Core/Exception.h"
namespace code {
STORM_PKG(core.asm);
namespace primitive {
// Kind of primitives.
enum PrimitiveKind {
none,
pointer,
integer,
real,
};
// C++ friendly name. Can not be used in function declarations visible to Storm.
typedef PrimitiveKind Kind;
// Get the name as a string.
const wchar *name(Kind kind);
}
/**
* Description of a primitive type. Used inside 'TypeDesc'.
*/
class Primitive {
STORM_VALUE;
public:
// Create a 'void' value.
STORM_CTOR Primitive();
// Create a primitive.
STORM_CTOR Primitive(primitive::PrimitiveKind kind, Size size, Offset offset);
// Get the kind.
inline primitive::PrimitiveKind STORM_FN kind() const {
return primitive::Kind((dataA & 0x1) | ((dataB & 0x1) << 1));
}
// Get the size (we do not preserve alignment).
inline Size STORM_FN size() const {
Nat s32 = (dataA & 0xFE) >> 1;
Nat s64 = (dataB & 0xFE) >> 1;
return Size(s32, s32, s64, s64);
}
// Get the offset.
inline Offset STORM_FN offset() const {
Nat o32 = (dataA & 0xFFFFFF00) >> 8;
Nat o64 = (dataB & 0xFFFFFF00) >> 8;
return Offset(o32, o64);
}
// Move to another offset.
Primitive STORM_FN move(Offset to) const;
// Output.
void STORM_FN toS(StrBuf *to) const;
private:
// We store these fields inside 'dataA' and 'dataB'.
// A0, B0: kind (A0 is LSB).
// A1-7: 32-bit size
// B1-7: 64-bit size
// A8-31: 32-bit offset
// B8-31: 64-bit offset
Nat dataA;
Nat dataB;
};
wostream &operator <<(wostream &to, const Primitive &p);
// Create primitive types easily.
inline Primitive STORM_FN bytePrimitive() { return Primitive(primitive::integer, Size::sByte, Offset()); }
inline Primitive STORM_FN intPrimitive() { return Primitive(primitive::integer, Size::sInt, Offset()); }
inline Primitive STORM_FN ptrPrimitive() { return Primitive(primitive::pointer, Size::sPtr, Offset()); }
inline Primitive STORM_FN longPrimitive() { return Primitive(primitive::integer, Size::sLong, Offset()); }
inline Primitive STORM_FN floatPrimitive() { return Primitive(primitive::real, Size::sFloat, Offset()); }
inline Primitive STORM_FN doublePrimitive() { return Primitive(primitive::real, Size::sDouble, Offset()); }
/**
* Low-level description of a type. Instances of this class are used to tell the code backend
* enough about a type that is being passed as a parameter so that it can properly follow the
* calling convention of the system being targeted.
*
* A TypeDesc may describe the following categories of types:
* - A primitive type (size, floating point)
* - A complex type (size, constructor, destructor)
* - A simple type (size and offset off all members)
*
* A primitive type is some kind of number that can be handled by the CPU (eg. int, float). In
* this case, we store the total size of the type and what kind of number we're dealing with
* (ie. pointer, integer, floating point).
*
* A complex type is a composite type (ie. struct or class) that can not be trivially
* copied. Therefore, we are only concerned with the total size of the type and its copy
* constructor and destructor.
*
* A simple type is a composite type (ie. struct or class) that can be trivially copied. This
* means we do not need to concern ourselves with the copy constructor and destructor of the
* type, but we need to know all members of the type. If the simple type contains other simple
* types, these are also disassembled until only primitive types remain.
*/
class TypeDesc : public ObjectOn<Compiler> {
STORM_CLASS;
public:
// Get the size of this type.
virtual Size STORM_FN size() const;
};
/**
* A primitive type:
*
* This is a type that the CPU can handle directly, and that can be stored in a register.
*/
class PrimitiveDesc : public TypeDesc {
STORM_CLASS;
public:
STORM_CTOR PrimitiveDesc(Primitive p);
Primitive v;
virtual Size STORM_FN size() const { return v.size(); }
void STORM_FN toS(StrBuf *to) const;
};
/**
* A complex type:
*
* This is a type that needs to reside in memory, and that needs to be manipulated through
* copy-constructors and destructors.
*/
class ComplexDesc : public TypeDesc {
STORM_CLASS;
public:
ComplexDesc(Size size, Ref ctor, Ref dtor);
Size s;
Ref ctor;
Ref dtor;
virtual Size STORM_FN size() const { return s; }
void STORM_FN toS(StrBuf *to) const;
};
/**
* A simple type:
*
* This is a type that consists of a set of primitive types. While it may not be possible to
* store the type in a register, it is possible to decompose the type into multiple registers
* and manipulate it in that way.
*/
class SimpleDesc : public TypeDesc {
STORM_CLASS;
public:
STORM_CTOR SimpleDesc(Size size, Nat entries);
// Total size:
Size s;
// Primitives. These are assumed to be sorted according to their offset.
GcArray<Primitive> *v;
Primitive &STORM_FN at(Nat id) {
if (id >= v->count)
throw new (this) storm::ArrayError(id, Nat(v->count));
return v->v[id];
}
Nat STORM_FN count() const {
return Nat(v->count);
}
// Sort primitives.
void STORM_FN sort();
// virtual void STORM_FN deepCopy(CloneEnv *env);
virtual Size STORM_FN size() const { return s; }
void STORM_FN toS(StrBuf *to) const;
};
/**
* Helpers for creating TypeDesc objects.
*/
TypeDesc *STORM_FN voidDesc(EnginePtr e);
TypeDesc *STORM_FN byteDesc(EnginePtr e);
TypeDesc *STORM_FN intDesc(EnginePtr e);
TypeDesc *STORM_FN ptrDesc(EnginePtr e);
TypeDesc *STORM_FN longDesc(EnginePtr e);
TypeDesc *STORM_FN floatDesc(EnginePtr e);
TypeDesc *STORM_FN doubleDesc(EnginePtr e);
}
|