| 46 | } |
| 47 | |
| 48 | inline Type GetMemoryType(Type operand_type, Opcode opc) { |
| 49 | // TODO: something something SIMD. |
| 50 | // TODO: this loses information of the type it is read into. |
| 51 | // That may well not be the biggest deal since that is usually obvious |
| 52 | // from context, if not, we should probably represent that as a cast around |
| 53 | // the access, since it should not be part of the field type. |
| 54 | if (operand_type == Type::I32 || operand_type == Type::I64) { |
| 55 | auto name = std::string_view(opc.GetName()); |
| 56 | // FIXME: change into a new column in opcode.def instead? |
| 57 | auto is_unsigned = name.substr(name.size() - 2) == "_u"; |
| 58 | switch (opc.GetMemorySize()) { |
| 59 | case 1: return is_unsigned ? Type::I8U : Type::I8; |
| 60 | case 2: return is_unsigned ? Type::I16U : Type::I16; |
| 61 | case 4: return is_unsigned ? Type::I32U : Type::I32; |
| 62 | } |
| 63 | } |
| 64 | return operand_type; |
| 65 | } |
| 66 | |
| 67 | // Track all loads and stores inside a single function, to be able to detect |
| 68 | // struct layouts we can use to annotate variables with, to make code more |
no test coverage detected