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
|
#pragma once
namespace code {
/**
* Make these functions more convenient to call in C++ during certain conditions:
*
* It inhibits the clarity and it is a bit annoying to have to do:
* *foo << mov(e, eax, ebx);
*
* instead of:
* *foo << mov(eax, ebx);
*
* The first engine parameter is not visible in Storm (as it will insert that for us
* automatically), but in C++ we need another mechanism as C++ does not know which engine we
* will use. So in the context of directly appending instructions to a Listing object, we can
* save the parameters in some container temporarily and delay the call to the actual creating
* function until the result is appended to a Listing. When this happens, we can get an Engine
* from there and create the Instr object properly. This is done with the template magic
* below. Sadly, we need to declare all machine operations once more at the end, but that is a
* small price to pay.
*/
template <Instr *(*Fn)(EnginePtr)>
class InstrProxy0 {};
template <Instr *(*Fn)(EnginePtr)>
inline Listing &operator <<(Listing &l, const InstrProxy0<Fn> &p) {
return l << (*Fn)(l.engine());
}
template <class T, Instr *(*Fn)(EnginePtr, T)>
class InstrProxy1 {
public:
const T &t;
InstrProxy1(const T &t) : t(t) {}
};
template <class T, Instr *(*Fn)(EnginePtr, T)>
inline Listing &operator <<(Listing &l, const InstrProxy1<T, Fn> &p) {
return l << (*Fn)(l.engine(), p.t);
}
template <class T, class U, Instr *(*Fn)(EnginePtr, T, U)>
class InstrProxy2 {
public:
const T &t;
const U &u;
InstrProxy2(const T &t, const U &u) : t(t), u(u) {}
};
template <class T, class U, Instr *(*Fn)(EnginePtr, T, U)>
inline Listing &operator <<(Listing &l, const InstrProxy2<T, U, Fn> &p) {
return l << (*Fn)(l.engine(), p.t, p.u);
}
template <class T, class U, class V, Instr *(*Fn)(EnginePtr, T, U, V)>
class InstrProxy3 {
public:
const T &t;
const U &u;
const V &v;
InstrProxy3(const T &t, const U &u, const V &v) : t(t), u(u), v(v) {}
};
template <class T, class U, class V, Instr *(*Fn)(EnginePtr, T, U, V)>
inline Listing &operator <<(Listing &l, const InstrProxy3<T, U, V, Fn> &p) {
return l << (*Fn)(l.engine(), p.t, p.u, p.v);
}
template <class T, class U, class V, class W, Instr *(*Fn)(EnginePtr, T, U, V, W)>
class InstrProxy4 {
public:
const T &t;
const U &u;
const V &v;
const W &w;
InstrProxy4(const T &t, const U &u, const V &v, const W &w) : t(t), u(u), v(v), w(w) {}
};
template <class T, class U, class V, class W, Instr *(*Fn)(EnginePtr, T, U, V, W)>
inline Listing &operator <<(Listing &l, const InstrProxy4<T, U, V, W, Fn> &p) {
return l << (*Fn)(l.engine(), p.t, p.u, p.v, p.w);
}
#define PROXY0(op) \
inline InstrProxy0<&op> op() { \
return InstrProxy0<&op>(); \
}
#define PROXY1(op, T) \
inline InstrProxy1<T, &op> op(T const &t) { \
return InstrProxy1<T, &op>(t); \
}
#define PROXY2(op, T, U) \
inline InstrProxy2<T, U, &op> op(T const &t, U const &u) { \
return InstrProxy2<T, U, &op>(t, u); \
}
#define PROXY3(op, T, U, V) \
inline InstrProxy3<T, U, V, &op> op(T const &t, U const &u, V const &v) { \
return InstrProxy3<T, U, V, &op>(t, u, v); \
}
#define PROXY4(op, T, U, V, W) \
inline InstrProxy4<T, U, V, W, &op> op(T const &t, U const &u, V const &v, W const &w) { \
return InstrProxy4<T, U, V, W, &op>(t, u, v, w); \
}
// Repetition of all OP-codes.
PROXY0(nop);
PROXY2(mov, Operand, Operand);
PROXY2(swap, Reg, Operand);
PROXY1(push, Operand);
PROXY1(pop, Operand);
PROXY0(pushFlags);
PROXY0(popFlags);
PROXY1(jmp, Operand);
PROXY2(jmp, Label, CondFlag);
PROXY2(call, Operand, Size);
PROXY1(ret, Size);
PROXY2(lea, Operand, Operand);
PROXY2(setCond, Operand, CondFlag);
PROXY2(fnParam, TypeDesc *, Operand);
PROXY2(fnParamRef, TypeDesc *, Operand);
PROXY2(fnCall, Operand, Bool);
PROXY4(fnCall, Operand, Bool, TypeDesc *, Operand);
PROXY4(fnCallRef, Operand, Bool, TypeDesc *, Operand);
PROXY1(fnRet, Operand);
PROXY1(fnRetRef, Operand);
PROXY0(fnRet);
PROXY2(bor, Operand, Operand);
PROXY2(band, Operand, Operand);
PROXY2(bxor, Operand, Operand);
PROXY1(bnot, Operand);
PROXY2(test, Operand, Operand);
PROXY2(add, Operand, Operand);
PROXY2(adc, Operand, Operand);
PROXY2(sub, Operand, Operand);
PROXY2(sbb, Operand, Operand);
PROXY2(cmp, Operand, Operand);
PROXY2(mul, Operand, Operand);
PROXY2(idiv, Operand, Operand);
PROXY2(imod, Operand, Operand);
PROXY2(udiv, Operand, Operand);
PROXY2(umod, Operand, Operand);
PROXY2(shl, Operand, Operand);
PROXY2(shr, Operand, Operand);
PROXY2(sar, Operand, Operand);
PROXY2(icast, Operand, Operand);
PROXY2(ucast, Operand, Operand);
PROXY2(fadd, Operand, Operand);
PROXY2(fsub, Operand, Operand);
PROXY2(fneg, Operand, Operand);
PROXY2(fmul, Operand, Operand);
PROXY2(fdiv, Operand, Operand);
PROXY2(fcmp, Operand, Operand);
PROXY2(fcast, Operand, Operand);
PROXY2(fcasti, Operand, Operand);
PROXY2(fcastu, Operand, Operand);
PROXY2(icastf, Operand, Operand);
PROXY2(ucastf, Operand, Operand);
PROXY1(fstp, Operand);
PROXY1(fld, Operand);
PROXY1(dat, Operand);
PROXY1(lblOffset, Label);
PROXY1(align, Offset);
PROXY1(alignAs, Size);
PROXY0(prolog);
PROXY0(epilog);
PROXY2(shadowMov, Operand, Operand);
PROXY2(preserve, Operand, Reg);
PROXY1(preserve, Reg);
PROXY1(location, SrcPos);
PROXY1(begin, Block);
PROXY1(end, Block);
PROXY2(jmpBlock, Label, Block);
PROXY1(activate, Var);
PROXY0(threadLocal);
}
|