Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1 | //===- subzero/src/WasmTranslator.cpp - WASM to Subzero Translation -------===// |
| 2 | // |
| 3 | // The Subzero Code Generator |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | /// |
| 10 | /// \file |
| 11 | /// \brief Defines a driver for translating Wasm bitcode into PNaCl bitcode. |
| 12 | /// |
| 13 | /// The translator uses V8's WebAssembly decoder to handle the binary Wasm |
| 14 | /// format but replaces the usual TurboFan builder with a new PNaCl builder. |
| 15 | /// |
| 16 | //===----------------------------------------------------------------------===// |
| 17 | |
John Porto | 681f90f | 2016-04-05 06:20:50 -0700 | [diff] [blame] | 18 | #if ALLOW_WASM |
| 19 | |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 20 | #include "WasmTranslator.h" |
| 21 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 22 | #ifdef __clang__ |
| 23 | #pragma clang diagnostic push |
| 24 | #pragma clang diagnostic ignored "-Wunused-parameter" |
| 25 | #pragma clang diagnostic ignored "-Wcovered-switch-default" |
| 26 | #endif // __clang__ |
| 27 | #if defined(__GNUC__) && !defined(__clang__) |
| 28 | #pragma GCC diagnostic push |
| 29 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" |
| 30 | #endif // defined(__GNUC__) && !defined(__clang__) |
| 31 | |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 32 | #include "src/wasm/module-decoder.h" |
| 33 | #include "src/wasm/wasm-opcodes.h" |
| 34 | #include "src/zone.h" |
| 35 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 36 | #include "src/bit-vector.h" |
| 37 | |
| 38 | #include "src/wasm/ast-decoder-impl.h" |
| 39 | |
| 40 | #ifdef __clang__ |
| 41 | #pragma clang diagnostic pop |
| 42 | #endif // __clang__ |
| 43 | #if defined(__GNUC__) && !defined(__clang__) |
| 44 | #pragma GCC diagnostic pop |
| 45 | #endif // defined(__GNUC__) && !defined(__clang__) |
| 46 | |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 47 | #include "IceCfgNode.h" |
| 48 | #include "IceGlobalInits.h" |
| 49 | |
| 50 | using namespace std; |
| 51 | using namespace Ice; |
| 52 | using namespace v8; |
| 53 | using namespace v8::internal; |
| 54 | using namespace v8::internal::wasm; |
| 55 | using v8::internal::wasm::DecodeWasmModule; |
| 56 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 57 | #undef LOG |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 58 | #define LOG(Expr) log([&](Ostream & out) { Expr; }) |
| 59 | |
| 60 | namespace { |
| 61 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 62 | std::string toStdString(WasmName Name) { |
| 63 | return std::string(Name.name, Name.length); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | Ice::Type toIceType(wasm::LocalType Type) { |
| 67 | switch (Type) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 68 | case MachineRepresentation::kNone: |
| 69 | llvm::report_fatal_error("kNone type not supported"); |
| 70 | case MachineRepresentation::kBit: |
| 71 | return IceType_i1; |
| 72 | case MachineRepresentation::kWord8: |
| 73 | return IceType_i8; |
| 74 | case MachineRepresentation::kWord16: |
| 75 | return IceType_i16; |
| 76 | case MachineRepresentation::kWord32: |
| 77 | return IceType_i32; |
| 78 | case MachineRepresentation::kWord64: |
| 79 | return IceType_i64; |
| 80 | case MachineRepresentation::kFloat32: |
| 81 | return IceType_f32; |
| 82 | case MachineRepresentation::kFloat64: |
| 83 | return IceType_f64; |
| 84 | case MachineRepresentation::kSimd128: |
| 85 | llvm::report_fatal_error("ambiguous SIMD type"); |
| 86 | case MachineRepresentation::kTagged: |
| 87 | llvm::report_fatal_error("kTagged type not supported"); |
| 88 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 89 | llvm::report_fatal_error("unexpected type"); |
| 90 | } |
| 91 | |
| 92 | Ice::Type toIceType(v8::internal::MachineType Type) { |
| 93 | // TODO (eholk): reorder these based on expected call frequency. |
| 94 | if (Type == MachineType::Int32()) { |
| 95 | return IceType_i32; |
| 96 | } |
| 97 | if (Type == MachineType::Uint32()) { |
| 98 | return IceType_i32; |
| 99 | } |
| 100 | if (Type == MachineType::Int8()) { |
| 101 | return IceType_i8; |
| 102 | } |
| 103 | if (Type == MachineType::Uint8()) { |
| 104 | return IceType_i8; |
| 105 | } |
| 106 | if (Type == MachineType::Int16()) { |
| 107 | return IceType_i16; |
| 108 | } |
| 109 | if (Type == MachineType::Uint16()) { |
| 110 | return IceType_i16; |
| 111 | } |
| 112 | if (Type == MachineType::Int64()) { |
| 113 | return IceType_i64; |
| 114 | } |
| 115 | if (Type == MachineType::Uint64()) { |
| 116 | return IceType_i64; |
| 117 | } |
| 118 | if (Type == MachineType::Float32()) { |
| 119 | return IceType_f32; |
| 120 | } |
| 121 | if (Type == MachineType::Float64()) { |
| 122 | return IceType_f64; |
| 123 | } |
| 124 | llvm::report_fatal_error("Unsupported MachineType"); |
| 125 | } |
| 126 | |
| 127 | std::string fnNameFromId(uint32_t Id) { |
| 128 | return std::string("fn") + to_string(Id); |
| 129 | } |
| 130 | |
| 131 | std::string getFunctionName(const WasmModule *Module, uint32_t func_index) { |
| 132 | // Try to find the function name in the export table |
| 133 | for (const auto Export : Module->export_table) { |
| 134 | if (Export.func_index == func_index) { |
| 135 | return "__szwasm_" + toStdString(Module->GetName(Export.name_offset, |
| 136 | Export.name_length)); |
| 137 | } |
| 138 | } |
| 139 | return fnNameFromId(func_index); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | } // end of anonymous namespace |
| 143 | |
| 144 | /// This class wraps either an Operand or a CfgNode. |
| 145 | /// |
| 146 | /// Turbofan's sea of nodes representation only has nodes for values, control |
| 147 | /// flow, etc. In Subzero these concepts are all separate. This class lets V8's |
| 148 | /// Wasm decoder treat Subzero objects as though they are all the same. |
| 149 | class OperandNode { |
| 150 | static constexpr uintptr_t NODE_FLAG = 1; |
| 151 | static constexpr uintptr_t UNDEF_PTR = (uintptr_t)-1; |
| 152 | |
| 153 | uintptr_t Data = UNDEF_PTR; |
| 154 | |
| 155 | public: |
| 156 | OperandNode() = default; |
| 157 | explicit OperandNode(Operand *Operand) |
| 158 | : Data(reinterpret_cast<uintptr_t>(Operand)) {} |
| 159 | explicit OperandNode(CfgNode *Node) |
| 160 | : Data(reinterpret_cast<uintptr_t>(Node) | NODE_FLAG) {} |
| 161 | explicit OperandNode(nullptr_t) : Data(UNDEF_PTR) {} |
| 162 | |
| 163 | operator Operand *() const { |
| 164 | if (UNDEF_PTR == Data) { |
| 165 | return nullptr; |
| 166 | } |
| 167 | if (!isOperand()) { |
| 168 | llvm::report_fatal_error("This OperandNode is not an Operand"); |
| 169 | } |
| 170 | return reinterpret_cast<Operand *>(Data); |
| 171 | } |
| 172 | |
| 173 | operator CfgNode *() const { |
| 174 | if (UNDEF_PTR == Data) { |
| 175 | return nullptr; |
| 176 | } |
| 177 | if (!isCfgNode()) { |
| 178 | llvm::report_fatal_error("This OperandNode is not a CfgNode"); |
| 179 | } |
| 180 | return reinterpret_cast<CfgNode *>(Data & ~NODE_FLAG); |
| 181 | } |
| 182 | |
| 183 | explicit operator bool() const { return (Data != UNDEF_PTR) && Data; } |
| 184 | bool operator==(const OperandNode &Rhs) const { |
| 185 | return (Data == Rhs.Data) || |
| 186 | (UNDEF_PTR == Data && (Rhs.Data == 0 || Rhs.Data == NODE_FLAG)) || |
| 187 | (UNDEF_PTR == Rhs.Data && (Data == 0 || Data == NODE_FLAG)); |
| 188 | } |
| 189 | bool operator!=(const OperandNode &Rhs) const { return !(*this == Rhs); } |
| 190 | |
| 191 | bool isOperand() const { return (Data != UNDEF_PTR) && !(Data & NODE_FLAG); } |
| 192 | bool isCfgNode() const { return (Data != UNDEF_PTR) && (Data & NODE_FLAG); } |
| 193 | |
| 194 | Operand *toOperand() const { return static_cast<Operand *>(*this); } |
| 195 | |
| 196 | CfgNode *toCfgNode() const { return static_cast<CfgNode *>(*this); } |
| 197 | }; |
| 198 | |
| 199 | Ostream &operator<<(Ostream &Out, const OperandNode &Op) { |
| 200 | if (Op.isOperand()) { |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 201 | const auto *Oper = Op.toOperand(); |
| 202 | Out << "(Operand*)" << Oper; |
| 203 | if (Oper) { |
| 204 | Out << "::" << Oper->getType(); |
| 205 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 206 | } else if (Op.isCfgNode()) { |
| 207 | Out << "(CfgNode*)" << Op.toCfgNode(); |
| 208 | } else { |
| 209 | Out << "nullptr"; |
| 210 | } |
| 211 | return Out; |
| 212 | } |
| 213 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 214 | bool isComparison(wasm::WasmOpcode Opcode) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 215 | switch (Opcode) { |
| 216 | case kExprI32Ne: |
| 217 | case kExprI64Ne: |
| 218 | case kExprI32Eq: |
| 219 | case kExprI64Eq: |
| 220 | case kExprI32LtS: |
| 221 | case kExprI64LtS: |
| 222 | case kExprI32LtU: |
| 223 | case kExprI64LtU: |
| 224 | case kExprI32GeS: |
| 225 | case kExprI64GeS: |
| 226 | case kExprI32GtS: |
| 227 | case kExprI64GtS: |
| 228 | case kExprI32GtU: |
| 229 | case kExprI64GtU: |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 230 | case kExprF32Ne: |
| 231 | case kExprF64Ne: |
| 232 | case kExprF32Le: |
| 233 | case kExprF64Le: |
| 234 | case kExprI32LeS: |
| 235 | case kExprI64LeS: |
| 236 | case kExprI32GeU: |
| 237 | case kExprI64GeU: |
| 238 | case kExprI32LeU: |
| 239 | case kExprI64LeU: |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 240 | return true; |
| 241 | default: |
| 242 | return false; |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | class IceBuilder { |
| 247 | using Node = OperandNode; |
| 248 | |
| 249 | IceBuilder() = delete; |
| 250 | IceBuilder(const IceBuilder &) = delete; |
| 251 | IceBuilder &operator=(const IceBuilder &) = delete; |
| 252 | |
| 253 | public: |
| 254 | explicit IceBuilder(class Cfg *Func) |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 255 | : ControlPtr(nullptr), Func(Func), Ctx(Func->getContext()) {} |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 256 | |
| 257 | /// Allocates a buffer of Nodes for use by V8. |
| 258 | Node *Buffer(size_t Count) { |
| 259 | LOG(out << "Buffer(" << Count << ")\n"); |
| 260 | return Func->allocateArrayOf<Node>(Count); |
| 261 | } |
| 262 | |
| 263 | Node Error() { llvm::report_fatal_error("Error"); } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 264 | Node Start(uint32_t Params) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 265 | LOG(out << "Start(" << Params << ") = "); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 266 | auto *Entry = Func->getEntryNode(); |
| 267 | assert(Entry); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 268 | LOG(out << Node(Entry) << "\n"); |
| 269 | return OperandNode(Entry); |
| 270 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 271 | Node Param(uint32_t Index, wasm::LocalType Type) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 272 | LOG(out << "Param(" << Index << ") = "); |
| 273 | auto *Arg = makeVariable(toIceType(Type)); |
| 274 | assert(Index == NextArg); |
| 275 | Func->addArg(Arg); |
| 276 | ++NextArg; |
| 277 | LOG(out << Node(Arg) << "\n"); |
| 278 | return OperandNode(Arg); |
| 279 | } |
| 280 | Node Loop(CfgNode *Entry) { |
| 281 | auto *Loop = Func->makeNode(); |
| 282 | LOG(out << "Loop(" << Entry << ") = " << Loop << "\n"); |
| 283 | Entry->appendInst(InstBr::create(Func, Loop)); |
| 284 | return OperandNode(Loop); |
| 285 | } |
| 286 | void Terminate(Node Effect, Node Control) { |
| 287 | // TODO(eholk): this is almost certainly wrong |
| 288 | LOG(out << "Terminate(" << Effect << ", " << Control << ")" |
| 289 | << "\n"); |
| 290 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 291 | Node Merge(uint32_t Count, Node *Controls) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 292 | LOG(out << "Merge(" << Count); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 293 | for (uint32_t i = 0; i < Count; ++i) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 294 | LOG(out << ", " << Controls[i]); |
| 295 | } |
| 296 | LOG(out << ") = "); |
| 297 | |
| 298 | auto *MergedNode = Func->makeNode(); |
| 299 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 300 | for (uint32_t i = 0; i < Count; ++i) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 301 | CfgNode *Control = Controls[i]; |
| 302 | Control->appendInst(InstBr::create(Func, MergedNode)); |
| 303 | } |
| 304 | LOG(out << (OperandNode)MergedNode << "\n"); |
| 305 | return OperandNode(MergedNode); |
| 306 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 307 | Node Phi(wasm::LocalType, uint32_t Count, Node *Vals, Node Control) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 308 | LOG(out << "Phi(" << Count << ", " << Control); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 309 | for (uint32_t i = 0; i < Count; ++i) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 310 | LOG(out << ", " << Vals[i]); |
| 311 | } |
| 312 | LOG(out << ") = "); |
| 313 | |
| 314 | const auto &InEdges = Control.toCfgNode()->getInEdges(); |
| 315 | assert(Count == InEdges.size()); |
| 316 | |
| 317 | assert(Count > 0); |
| 318 | |
| 319 | auto *Dest = makeVariable(Vals[0].toOperand()->getType(), Control); |
| 320 | |
| 321 | // Multiply by 10 in case more things get added later. |
| 322 | |
| 323 | // TODO(eholk): find a better way besides multiplying by some arbitrary |
| 324 | // constant. |
| 325 | auto *Phi = InstPhi::create(Func, Count * 10, Dest); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 326 | for (uint32_t i = 0; i < Count; ++i) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 327 | auto *Op = Vals[i].toOperand(); |
| 328 | assert(Op); |
| 329 | Phi->addArgument(Op, InEdges[i]); |
| 330 | } |
| 331 | setDefiningInst(Dest, Phi); |
| 332 | Control.toCfgNode()->appendInst(Phi); |
| 333 | LOG(out << Node(Dest) << "\n"); |
| 334 | return OperandNode(Dest); |
| 335 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 336 | Node EffectPhi(uint32_t Count, Node *Effects, Node Control) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 337 | // TODO(eholk): this function is almost certainly wrong. |
| 338 | LOG(out << "EffectPhi(" << Count << ", " << Control << "):\n"); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 339 | for (uint32_t i = 0; i < Count; ++i) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 340 | LOG(out << " " << Effects[i] << "\n"); |
| 341 | } |
| 342 | return OperandNode(nullptr); |
| 343 | } |
| 344 | Node Int32Constant(int32_t Value) { |
| 345 | LOG(out << "Int32Constant(" << Value << ") = "); |
| 346 | auto *Const = Ctx->getConstantInt32(Value); |
| 347 | assert(Const); |
| 348 | assert(Control()); |
| 349 | LOG(out << Node(Const) << "\n"); |
| 350 | return OperandNode(Const); |
| 351 | } |
| 352 | Node Int64Constant(int64_t Value) { |
| 353 | LOG(out << "Int64Constant(" << Value << ") = "); |
| 354 | auto *Const = Ctx->getConstantInt64(Value); |
| 355 | assert(Const); |
| 356 | LOG(out << Node(Const) << "\n"); |
| 357 | return OperandNode(Const); |
| 358 | } |
| 359 | Node Float32Constant(float Value) { |
| 360 | LOG(out << "Float32Constant(" << Value << ") = "); |
| 361 | auto *Const = Ctx->getConstantFloat(Value); |
| 362 | assert(Const); |
| 363 | LOG(out << Node(Const) << "\n"); |
| 364 | return OperandNode(Const); |
| 365 | } |
| 366 | Node Float64Constant(double Value) { |
| 367 | LOG(out << "Float64Constant(" << Value << ") = "); |
| 368 | auto *Const = Ctx->getConstantDouble(Value); |
| 369 | assert(Const); |
| 370 | LOG(out << Node(Const) << "\n"); |
| 371 | return OperandNode(Const); |
| 372 | } |
| 373 | Node Binop(wasm::WasmOpcode Opcode, Node Left, Node Right) { |
| 374 | LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left |
| 375 | << ", " << Right << ") = "); |
| 376 | auto *Dest = makeVariable( |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 377 | isComparison(Opcode) ? IceType_i32 : Left.toOperand()->getType()); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 378 | switch (Opcode) { |
| 379 | case kExprI32Add: |
| 380 | case kExprI64Add: |
| 381 | Control()->appendInst( |
| 382 | InstArithmetic::create(Func, InstArithmetic::Add, Dest, Left, Right)); |
| 383 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 384 | case kExprF32Add: |
| 385 | case kExprF64Add: |
| 386 | Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Fadd, |
| 387 | Dest, Left, Right)); |
| 388 | break; |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 389 | case kExprI32Sub: |
| 390 | case kExprI64Sub: |
| 391 | Control()->appendInst( |
| 392 | InstArithmetic::create(Func, InstArithmetic::Sub, Dest, Left, Right)); |
| 393 | break; |
| 394 | case kExprI32Mul: |
| 395 | case kExprI64Mul: |
| 396 | Control()->appendInst( |
| 397 | InstArithmetic::create(Func, InstArithmetic::Mul, Dest, Left, Right)); |
| 398 | break; |
| 399 | case kExprI32DivU: |
| 400 | case kExprI64DivU: |
| 401 | Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Udiv, |
| 402 | Dest, Left, Right)); |
| 403 | break; |
| 404 | case kExprI32RemU: |
| 405 | case kExprI64RemU: |
| 406 | Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Urem, |
| 407 | Dest, Left, Right)); |
| 408 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 409 | case kExprI32RemS: |
| 410 | case kExprI64RemS: |
| 411 | Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Srem, |
| 412 | Dest, Left, Right)); |
| 413 | break; |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 414 | case kExprI32Ior: |
| 415 | case kExprI64Ior: |
| 416 | Control()->appendInst( |
| 417 | InstArithmetic::create(Func, InstArithmetic::Or, Dest, Left, Right)); |
| 418 | break; |
| 419 | case kExprI32Xor: |
| 420 | case kExprI64Xor: |
| 421 | Control()->appendInst( |
| 422 | InstArithmetic::create(Func, InstArithmetic::Xor, Dest, Left, Right)); |
| 423 | break; |
| 424 | case kExprI32Shl: |
| 425 | case kExprI64Shl: |
| 426 | Control()->appendInst( |
| 427 | InstArithmetic::create(Func, InstArithmetic::Shl, Dest, Left, Right)); |
| 428 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 429 | case kExprI32Rol: { |
| 430 | // TODO(eholk): add rotate as an ICE instruction to make it easier to take |
| 431 | // advantage of hardware support. |
| 432 | |
| 433 | // TODO(eholk): don't hardcode so many numbers. |
| 434 | auto *Masked = makeVariable(IceType_i32); |
| 435 | auto *Bottom = makeVariable(IceType_i32); |
| 436 | auto *Top = makeVariable(IceType_i32); |
| 437 | Control()->appendInst(InstArithmetic::create( |
| 438 | Func, InstArithmetic::And, Masked, Right, Ctx->getConstantInt32(31))); |
| 439 | Control()->appendInst( |
| 440 | InstArithmetic::create(Func, InstArithmetic::Shl, Top, Left, Masked)); |
| 441 | auto *RotShift = makeVariable(IceType_i32); |
| 442 | Control()->appendInst( |
| 443 | InstArithmetic::create(Func, InstArithmetic::Sub, RotShift, |
| 444 | Ctx->getConstantInt32(32), Masked)); |
| 445 | Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Lshr, |
| 446 | Bottom, Left, Masked)); |
| 447 | Control()->appendInst( |
| 448 | InstArithmetic::create(Func, InstArithmetic::Or, Dest, Top, Bottom)); |
| 449 | break; |
| 450 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 451 | case kExprI32ShrU: |
| 452 | case kExprI64ShrU: |
| 453 | case kExprI32ShrS: |
| 454 | case kExprI64ShrS: |
| 455 | Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Ashr, |
| 456 | Dest, Left, Right)); |
| 457 | break; |
| 458 | case kExprI32And: |
| 459 | case kExprI64And: |
| 460 | Control()->appendInst( |
| 461 | InstArithmetic::create(Func, InstArithmetic::And, Dest, Left, Right)); |
| 462 | break; |
| 463 | case kExprI32Ne: |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 464 | case kExprI64Ne: { |
| 465 | auto *TmpDest = makeVariable(IceType_i1); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 466 | Control()->appendInst( |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 467 | InstIcmp::create(Func, InstIcmp::Ne, TmpDest, Left, Right)); |
| 468 | Control()->appendInst( |
| 469 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 470 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 471 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 472 | case kExprI32Eq: |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 473 | case kExprI64Eq: { |
| 474 | auto *TmpDest = makeVariable(IceType_i1); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 475 | Control()->appendInst( |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 476 | InstIcmp::create(Func, InstIcmp::Eq, TmpDest, Left, Right)); |
| 477 | Control()->appendInst( |
| 478 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 479 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 480 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 481 | case kExprI32LtS: |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 482 | case kExprI64LtS: { |
| 483 | auto *TmpDest = makeVariable(IceType_i1); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 484 | Control()->appendInst( |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 485 | InstIcmp::create(Func, InstIcmp::Slt, TmpDest, Left, Right)); |
| 486 | Control()->appendInst( |
| 487 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 488 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 489 | } |
| 490 | case kExprI32LeS: |
| 491 | case kExprI64LeS: { |
| 492 | auto *TmpDest = makeVariable(IceType_i1); |
| 493 | Control()->appendInst( |
| 494 | InstIcmp::create(Func, InstIcmp::Sle, TmpDest, Left, Right)); |
| 495 | Control()->appendInst( |
| 496 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| 497 | break; |
| 498 | } |
| 499 | case kExprI32GeU: |
| 500 | case kExprI64GeU: { |
| 501 | auto *TmpDest = makeVariable(IceType_i1); |
| 502 | Control()->appendInst( |
| 503 | InstIcmp::create(Func, InstIcmp::Uge, TmpDest, Left, Right)); |
| 504 | Control()->appendInst( |
| 505 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| 506 | break; |
| 507 | } |
| 508 | case kExprI32LeU: |
| 509 | case kExprI64LeU: { |
| 510 | auto *TmpDest = makeVariable(IceType_i1); |
| 511 | Control()->appendInst( |
| 512 | InstIcmp::create(Func, InstIcmp::Ule, TmpDest, Left, Right)); |
| 513 | Control()->appendInst( |
| 514 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| 515 | break; |
| 516 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 517 | case kExprI32LtU: |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 518 | case kExprI64LtU: { |
| 519 | auto *TmpDest = makeVariable(IceType_i1); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 520 | Control()->appendInst( |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 521 | InstIcmp::create(Func, InstIcmp::Ult, TmpDest, Left, Right)); |
| 522 | Control()->appendInst( |
| 523 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 524 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 525 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 526 | case kExprI32GeS: |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 527 | case kExprI64GeS: { |
| 528 | auto *TmpDest = makeVariable(IceType_i1); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 529 | Control()->appendInst( |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 530 | InstIcmp::create(Func, InstIcmp::Sge, TmpDest, Left, Right)); |
| 531 | Control()->appendInst( |
| 532 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| 533 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 534 | case kExprI32GtS: |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 535 | case kExprI64GtS: { |
| 536 | auto *TmpDest = makeVariable(IceType_i1); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 537 | Control()->appendInst( |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 538 | InstIcmp::create(Func, InstIcmp::Sgt, TmpDest, Left, Right)); |
| 539 | Control()->appendInst( |
| 540 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 541 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 542 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 543 | case kExprI32GtU: |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 544 | case kExprI64GtU: { |
| 545 | auto *TmpDest = makeVariable(IceType_i1); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 546 | Control()->appendInst( |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 547 | InstIcmp::create(Func, InstIcmp::Ugt, TmpDest, Left, Right)); |
| 548 | Control()->appendInst( |
| 549 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 550 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 551 | } |
| 552 | case kExprF32Ne: |
| 553 | case kExprF64Ne: { |
| 554 | auto *TmpDest = makeVariable(IceType_i1); |
| 555 | Control()->appendInst( |
| 556 | InstFcmp::create(Func, InstFcmp::Une, TmpDest, Left, Right)); |
| 557 | Control()->appendInst( |
| 558 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| 559 | break; |
| 560 | } |
| 561 | case kExprF32Le: |
| 562 | case kExprF64Le: { |
| 563 | auto *TmpDest = makeVariable(IceType_i1); |
| 564 | Control()->appendInst( |
| 565 | InstFcmp::create(Func, InstFcmp::Ule, TmpDest, Left, Right)); |
| 566 | Control()->appendInst( |
| 567 | InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| 568 | break; |
| 569 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 570 | default: |
| 571 | LOG(out << "Unknown binop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); |
| 572 | llvm::report_fatal_error("Uncovered or invalid binop."); |
| 573 | return OperandNode(nullptr); |
| 574 | } |
| 575 | LOG(out << Dest << "\n"); |
| 576 | return OperandNode(Dest); |
| 577 | } |
| 578 | Node Unop(wasm::WasmOpcode Opcode, Node Input) { |
| 579 | LOG(out << "Unop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Input |
| 580 | << ") = "); |
| 581 | Ice::Variable *Dest = nullptr; |
| 582 | switch (Opcode) { |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 583 | case kExprI32Eqz: { |
| 584 | Dest = makeVariable(IceType_i32); |
| 585 | auto *Tmp = makeVariable(IceType_i1); |
| 586 | Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input, |
| 587 | Ctx->getConstantInt32(0))); |
| 588 | Control()->appendInst(InstCast::create(Func, InstCast::Sext, Dest, Tmp)); |
| 589 | break; |
| 590 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 591 | case kExprF32Neg: { |
| 592 | Dest = makeVariable(IceType_f32); |
| 593 | Control()->appendInst(InstArithmetic::create( |
| 594 | Func, InstArithmetic::Fsub, Dest, Ctx->getConstantFloat(0), Input)); |
| 595 | break; |
| 596 | } |
| 597 | case kExprF64Neg: { |
| 598 | Dest = makeVariable(IceType_f64); |
| 599 | Control()->appendInst(InstArithmetic::create( |
| 600 | Func, InstArithmetic::Fsub, Dest, Ctx->getConstantDouble(0), Input)); |
| 601 | break; |
| 602 | } |
| 603 | case kExprI64UConvertI32: |
| 604 | Dest = makeVariable(IceType_i64); |
| 605 | Control()->appendInst( |
| 606 | InstCast::create(Func, InstCast::Zext, Dest, Input)); |
| 607 | break; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 608 | case kExprI64SConvertI32: |
| 609 | Dest = makeVariable(IceType_i64); |
| 610 | Control()->appendInst( |
| 611 | InstCast::create(Func, InstCast::Sext, Dest, Input)); |
| 612 | break; |
| 613 | case kExprI32ConvertI64: |
| 614 | Dest = makeVariable(IceType_i32); |
| 615 | Control()->appendInst( |
| 616 | InstCast::create(Func, InstCast::Trunc, Dest, Input)); |
| 617 | break; |
| 618 | case kExprF64SConvertI32: |
| 619 | Dest = makeVariable(IceType_f64); |
| 620 | Control()->appendInst( |
| 621 | InstCast::create(Func, InstCast::Sitofp, Dest, Input)); |
| 622 | break; |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 623 | default: |
| 624 | LOG(out << "Unknown unop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); |
| 625 | llvm::report_fatal_error("Uncovered or invalid unop."); |
| 626 | return OperandNode(nullptr); |
| 627 | } |
| 628 | LOG(out << Dest << "\n"); |
| 629 | return OperandNode(Dest); |
| 630 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 631 | uint32_t InputCount(CfgNode *Node) const { return Node->getInEdges().size(); } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 632 | bool IsPhiWithMerge(Node Phi, Node Merge) const { |
| 633 | LOG(out << "IsPhiWithMerge(" << Phi << ", " << Merge << ")" |
| 634 | << "\n"); |
| 635 | if (Phi && Phi.isOperand()) { |
| 636 | LOG(out << " ...is operand" |
| 637 | << "\n"); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 638 | if (getDefiningInst(Phi)) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 639 | LOG(out << " ...has defining instruction" |
| 640 | << "\n"); |
| 641 | LOG(out << getDefNode(Phi) << "\n"); |
| 642 | LOG(out << " ..." << (getDefNode(Phi) == Merge) << "\n"); |
| 643 | return getDefNode(Phi) == Merge; |
| 644 | } |
| 645 | } |
| 646 | return false; |
| 647 | } |
| 648 | void AppendToMerge(CfgNode *Merge, CfgNode *From) const { |
| 649 | From->appendInst(InstBr::create(Func, Merge)); |
| 650 | } |
| 651 | void AppendToPhi(Node Merge, Node Phi, Node From) { |
| 652 | LOG(out << "AppendToPhi(" << Merge << ", " << Phi << ", " << From << ")" |
| 653 | << "\n"); |
| 654 | auto *Inst = getDefiningInst(Phi); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 655 | assert(Inst->getDest()->getType() == From.toOperand()->getType()); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 656 | Inst->addArgument(From, getDefNode(From)); |
| 657 | } |
| 658 | |
| 659 | //----------------------------------------------------------------------- |
| 660 | // Operations that read and/or write {control} and {effect}. |
| 661 | //----------------------------------------------------------------------- |
| 662 | Node Branch(Node Cond, Node *TrueNode, Node *FalseNode) { |
| 663 | // true_node and false_node appear to be out parameters. |
| 664 | LOG(out << "Branch(" << Cond << ", "); |
| 665 | |
| 666 | // save control here because true_node appears to alias control. |
| 667 | auto *Ctrl = Control(); |
| 668 | |
| 669 | *TrueNode = OperandNode(Func->makeNode()); |
| 670 | *FalseNode = OperandNode(Func->makeNode()); |
| 671 | |
| 672 | LOG(out << *TrueNode << ", " << *FalseNode << ")" |
| 673 | << "\n"); |
| 674 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 675 | auto *CondBool = makeVariable(IceType_i1); |
| 676 | Ctrl->appendInst(InstCast::create(Func, InstCast::Trunc, CondBool, Cond)); |
| 677 | |
| 678 | Ctrl->appendInst(InstBr::create(Func, CondBool, *TrueNode, *FalseNode)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 679 | return OperandNode(nullptr); |
| 680 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 681 | InstSwitch *CurrentSwitch = nullptr; |
| 682 | CfgNode *SwitchNode = nullptr; |
| 683 | SizeT SwitchIndex = 0; |
| 684 | Node Switch(uint32_t Count, Node Key) { |
| 685 | LOG(out << "Switch(" << Count << ", " << Key << ")\n"); |
| 686 | |
| 687 | assert(!CurrentSwitch); |
| 688 | |
| 689 | auto *Default = Func->makeNode(); |
| 690 | // Count - 1 because the decoder counts the default label but Subzero does |
| 691 | // not. |
| 692 | CurrentSwitch = InstSwitch::create(Func, Count - 1, Key, Default); |
| 693 | SwitchIndex = 0; |
| 694 | SwitchNode = Control(); |
| 695 | // We don't actually append the switch to the CfgNode here because not all |
| 696 | // the branches are ready. |
| 697 | return Node(nullptr); |
| 698 | } |
| 699 | Node IfValue(int32_t Value, Node) { |
| 700 | LOG(out << "IfValue(" << Value << ") [Index = " << SwitchIndex << "]\n"); |
| 701 | assert(CurrentSwitch); |
| 702 | auto *Target = Func->makeNode(); |
| 703 | CurrentSwitch->addBranch(SwitchIndex++, Value, Target); |
| 704 | return Node(Target); |
| 705 | } |
| 706 | Node IfDefault(Node) { |
| 707 | LOG(out << "IfDefault(...) [Index = " << SwitchIndex << "]\n"); |
| 708 | assert(CurrentSwitch); |
| 709 | assert(CurrentSwitch->getLabelDefault()); |
| 710 | // Now we append the switch, since this should be the last edge. |
| 711 | assert(SwitchIndex == CurrentSwitch->getNumCases()); |
| 712 | SwitchNode->appendInst(CurrentSwitch); |
| 713 | SwitchNode = nullptr; |
| 714 | auto Default = Node(CurrentSwitch->getLabelDefault()); |
| 715 | CurrentSwitch = nullptr; |
| 716 | return Default; |
| 717 | } |
| 718 | Node Return(uint32_t Count, Node *Vals) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 719 | assert(1 >= Count); |
| 720 | LOG(out << "Return("); |
| 721 | if (Count > 0) |
| 722 | LOG(out << Vals[0]); |
| 723 | LOG(out << ")" |
| 724 | << "\n"); |
| 725 | auto *Instr = |
| 726 | 1 == Count ? InstRet::create(Func, Vals[0]) : InstRet::create(Func); |
| 727 | Control()->appendInst(Instr); |
| 728 | Control()->setHasReturn(); |
| 729 | LOG(out << Node(nullptr) << "\n"); |
| 730 | return OperandNode(nullptr); |
| 731 | } |
| 732 | Node ReturnVoid() { |
| 733 | LOG(out << "ReturnVoid() = "); |
| 734 | auto *Instr = InstRet::create(Func); |
| 735 | Control()->appendInst(Instr); |
| 736 | Control()->setHasReturn(); |
| 737 | LOG(out << Node(nullptr) << "\n"); |
| 738 | return OperandNode(nullptr); |
| 739 | } |
| 740 | Node Unreachable() { |
| 741 | LOG(out << "Unreachable() = "); |
| 742 | auto *Instr = InstUnreachable::create(Func); |
| 743 | Control()->appendInst(Instr); |
| 744 | LOG(out << Node(nullptr) << "\n"); |
| 745 | return OperandNode(nullptr); |
| 746 | } |
| 747 | |
| 748 | Node CallDirect(uint32_t Index, Node *Args) { |
| 749 | LOG(out << "CallDirect(" << Index << ")" |
| 750 | << "\n"); |
| 751 | assert(Module->IsValidFunction(Index)); |
| 752 | const auto *Module = this->Module->module; |
| 753 | assert(Module); |
| 754 | const auto &Target = Module->functions[Index]; |
| 755 | const auto *Sig = Target.sig; |
| 756 | assert(Sig); |
| 757 | const auto NumArgs = Sig->parameter_count(); |
| 758 | LOG(out << " number of args: " << NumArgs << "\n"); |
| 759 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 760 | const auto TargetName = getFunctionName(Module, Index); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 761 | LOG(out << " target name: " << TargetName << "\n"); |
| 762 | |
| 763 | assert(Sig->return_count() <= 1); |
| 764 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 765 | auto TargetOperand = |
| 766 | Ctx->getConstantSym(0, Ctx->getGlobalString(TargetName)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 767 | |
| 768 | auto *Dest = Sig->return_count() > 0 |
| 769 | ? makeVariable(toIceType(Sig->GetReturn())) |
| 770 | : nullptr; |
| 771 | auto *Call = InstCall::create(Func, NumArgs, Dest, TargetOperand, |
| 772 | false /* HasTailCall */); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 773 | for (uint32_t i = 0; i < NumArgs; ++i) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 774 | // The builder reserves the first argument for the code object. |
| 775 | LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n"); |
| 776 | Call->addArg(Args[i + 1]); |
| 777 | } |
| 778 | |
| 779 | Control()->appendInst(Call); |
| 780 | LOG(out << "Call Result = " << Node(Dest) << "\n"); |
| 781 | return OperandNode(Dest); |
| 782 | } |
| 783 | Node CallImport(uint32_t Index, Node *Args) { |
| 784 | LOG(out << "CallImport(" << Index << ")" |
| 785 | << "\n"); |
| 786 | const auto *Module = this->Module->module; |
| 787 | assert(Module); |
| 788 | const auto *Sig = this->Module->GetImportSignature(Index); |
| 789 | assert(Sig); |
| 790 | const auto NumArgs = Sig->parameter_count(); |
| 791 | LOG(out << " number of args: " << NumArgs << "\n"); |
| 792 | |
| 793 | const auto &Target = Module->import_table[Index]; |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 794 | const auto ModuleName = toStdString( |
| 795 | Module->GetName(Target.module_name_offset, Target.module_name_length)); |
| 796 | const auto FnName = toStdString(Module->GetName( |
| 797 | Target.function_name_offset, Target.function_name_length)); |
| 798 | |
| 799 | const auto TargetName = Ctx->getGlobalString(ModuleName + "$$" + FnName); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 800 | LOG(out << " target name: " << TargetName << "\n"); |
| 801 | |
| 802 | assert(Sig->return_count() <= 1); |
| 803 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 804 | auto TargetOperand = Ctx->getConstantExternSym(TargetName); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 805 | |
| 806 | auto *Dest = Sig->return_count() > 0 |
| 807 | ? makeVariable(toIceType(Sig->GetReturn())) |
| 808 | : nullptr; |
| 809 | constexpr bool NoTailCall = false; |
| 810 | auto *Call = |
| 811 | InstCall::create(Func, NumArgs, Dest, TargetOperand, NoTailCall); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 812 | for (uint32_t i = 0; i < NumArgs; ++i) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 813 | // The builder reserves the first argument for the code object. |
| 814 | LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n"); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 815 | assert(Args[i + 1].toOperand()->getType() == toIceType(Sig->GetParam(i))); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 816 | Call->addArg(Args[i + 1]); |
| 817 | } |
| 818 | |
| 819 | Control()->appendInst(Call); |
| 820 | LOG(out << "Call Result = " << Node(Dest) << "\n"); |
| 821 | return OperandNode(Dest); |
| 822 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 823 | Node CallIndirect(uint32_t SigIndex, Node *Args) { |
| 824 | LOG(out << "CallIndirect(" << SigIndex << ")\n"); |
| 825 | // TODO(eholk): Compile to something better than a switch. |
| 826 | const auto *Module = this->Module->module; |
| 827 | assert(Module); |
| 828 | const auto &IndirectTable = Module->function_table; |
| 829 | |
| 830 | // TODO(eholk): This should probably actually call abort instead. |
| 831 | auto *Abort = Func->makeNode(); |
| 832 | Abort->appendInst(InstUnreachable::create(Func)); |
| 833 | |
| 834 | assert(Args[0].toOperand()); |
| 835 | |
| 836 | auto *Switch = InstSwitch::create(Func, IndirectTable.size(), |
| 837 | Args[0].toOperand(), Abort); |
| 838 | assert(Abort); |
| 839 | |
| 840 | const bool HasReturn = Module->signatures[SigIndex]->return_count() != 0; |
| 841 | const Ice::Type DestTy = |
| 842 | HasReturn ? toIceType(Module->signatures[SigIndex]->GetReturn()) |
| 843 | : IceType_void; |
| 844 | |
| 845 | auto *Dest = HasReturn ? makeVariable(DestTy) : nullptr; |
| 846 | |
| 847 | auto *ExitNode = Func->makeNode(); |
| 848 | auto *PhiInst = |
| 849 | HasReturn ? InstPhi::create(Func, IndirectTable.size(), Dest) : nullptr; |
| 850 | |
| 851 | for (uint32_t Index = 0; Index < IndirectTable.size(); ++Index) { |
| 852 | const auto &Target = Module->functions[IndirectTable[Index]]; |
| 853 | |
| 854 | if (SigIndex == Target.sig_index) { |
| 855 | auto *CallNode = Func->makeNode(); |
| 856 | auto *SavedControl = Control(); |
| 857 | *ControlPtr = OperandNode(CallNode); |
| 858 | auto *Tmp = CallDirect(Target.func_index, Args).toOperand(); |
| 859 | *ControlPtr = OperandNode(SavedControl); |
| 860 | if (PhiInst) { |
| 861 | PhiInst->addArgument(Tmp, CallNode); |
| 862 | } |
| 863 | CallNode->appendInst(InstBr::create(Func, ExitNode)); |
| 864 | Switch->addBranch(Index, Index, CallNode); |
| 865 | } else { |
| 866 | Switch->addBranch(Index, Index, Abort); |
| 867 | } |
| 868 | } |
| 869 | |
| 870 | if (PhiInst) { |
| 871 | ExitNode->appendInst(PhiInst); |
| 872 | } |
| 873 | |
| 874 | Control()->appendInst(Switch); |
| 875 | *ControlPtr = OperandNode(ExitNode); |
| 876 | return OperandNode(Dest); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 877 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 878 | Node Invert(Node Node) { |
| 879 | (void)Node; |
| 880 | llvm::report_fatal_error("Invert"); |
| 881 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 882 | |
| 883 | //----------------------------------------------------------------------- |
| 884 | // Operations that concern the linear memory. |
| 885 | //----------------------------------------------------------------------- |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 886 | Node MemSize(uint32_t Offset) { |
| 887 | (void)Offset; |
| 888 | llvm::report_fatal_error("MemSize"); |
| 889 | } |
| 890 | Node LoadGlobal(uint32_t Index) { |
| 891 | (void)Index; |
| 892 | llvm::report_fatal_error("LoadGlobal"); |
| 893 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 894 | Node StoreGlobal(uint32_t Index, Node Val) { |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 895 | (void)Index; |
| 896 | (void)Val; |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 897 | llvm::report_fatal_error("StoreGlobal"); |
| 898 | } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 899 | |
| 900 | Operand *sanitizeAddress(Operand *Base, uint32_t Offset) { |
| 901 | // first, add the index and the offset together. |
| 902 | if (0 != Offset) { |
| 903 | auto *Addr = makeVariable(IceType_i32); |
| 904 | auto *OffsetConstant = Ctx->getConstantInt32(Offset); |
| 905 | Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add, |
| 906 | Addr, Base, OffsetConstant)); |
| 907 | Base = Addr; |
| 908 | } |
| 909 | |
| 910 | SizeT MemSize = Module->module->min_mem_pages * (16 << 10); |
| 911 | auto *WrappedAddr = makeVariable(IceType_i32); |
| 912 | Control()->appendInst( |
| 913 | InstArithmetic::create(Func, InstArithmetic::Add, WrappedAddr, Base, |
| 914 | Ctx->getConstantInt32(MemSize))); |
| 915 | |
| 916 | auto ClampedAddr = makeVariable(IceType_i32); |
| 917 | Control()->appendInst( |
| 918 | InstArithmetic::create(Func, InstArithmetic::And, ClampedAddr, Base, |
| 919 | Ctx->getConstantInt32(MemSize - 1))); |
| 920 | |
| 921 | auto RealAddr = Func->makeVariable(IceType_i32); |
| 922 | auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY")); |
| 923 | Control()->appendInst(InstArithmetic::create( |
| 924 | Func, InstArithmetic::Add, RealAddr, ClampedAddr, MemBase)); |
| 925 | return RealAddr; |
| 926 | } |
| 927 | |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 928 | Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index, |
| 929 | uint32_t Offset) { |
| 930 | LOG(out << "LoadMem(" << Index << "[" << Offset << "]) = "); |
| 931 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 932 | auto *RealAddr = sanitizeAddress(Index, Offset); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 933 | |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 934 | auto *LoadResult = makeVariable(toIceType(MemType)); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 935 | Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 936 | |
| 937 | // and cast, if needed |
| 938 | Ice::Variable *Result = nullptr; |
| 939 | if (toIceType(Type) != toIceType(MemType)) { |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 940 | auto DestType = toIceType(Type); |
| 941 | Result = makeVariable(DestType); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 942 | // TODO(eholk): handle signs correctly. |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 943 | if (isScalarIntegerType(DestType)) { |
| 944 | if (MemType.IsSigned()) { |
| 945 | Control()->appendInst( |
| 946 | InstCast::create(Func, InstCast::Sext, Result, LoadResult)); |
| 947 | } else { |
| 948 | Control()->appendInst( |
| 949 | InstCast::create(Func, InstCast::Zext, Result, LoadResult)); |
| 950 | } |
| 951 | } else if (isScalarFloatingType(DestType)) { |
| 952 | Control()->appendInst( |
| 953 | InstCast::create(Func, InstCast::Sitofp, Result, LoadResult)); |
| 954 | } else { |
| 955 | llvm::report_fatal_error("Unsupported type for memory load"); |
| 956 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 957 | } else { |
| 958 | Result = LoadResult; |
| 959 | } |
| 960 | |
| 961 | LOG(out << Result << "\n"); |
| 962 | return OperandNode(Result); |
| 963 | } |
| 964 | void StoreMem(MachineType Type, Node Index, uint32_t Offset, Node Val) { |
| 965 | LOG(out << "StoreMem(" << Index << "[" << Offset << "] = " << Val << ")" |
| 966 | << "\n"); |
| 967 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 968 | auto *RealAddr = sanitizeAddress(Index, Offset); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 969 | |
| 970 | // cast the value to the right type, if needed |
| 971 | Operand *StoreVal = nullptr; |
| 972 | if (toIceType(Type) != Val.toOperand()->getType()) { |
| 973 | auto *LocalStoreVal = makeVariable(toIceType(Type)); |
| 974 | Control()->appendInst( |
| 975 | InstCast::create(Func, InstCast::Trunc, LocalStoreVal, Val)); |
| 976 | StoreVal = LocalStoreVal; |
| 977 | } else { |
| 978 | StoreVal = Val; |
| 979 | } |
| 980 | |
| 981 | // then store the memory |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 982 | Control()->appendInst(InstStore::create(Func, StoreVal, RealAddr)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 983 | } |
| 984 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 985 | static void PrintDebugName(OperandNode Node) { |
| 986 | (void)Node; |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 987 | llvm::report_fatal_error("PrintDebugName"); |
| 988 | } |
| 989 | |
| 990 | CfgNode *Control() { |
| 991 | return ControlPtr ? ControlPtr->toCfgNode() : Func->getEntryNode(); |
| 992 | } |
| 993 | Node Effect() { return *EffectPtr; } |
| 994 | |
| 995 | void set_module(wasm::ModuleEnv *Module) { this->Module = Module; } |
| 996 | |
| 997 | void set_control_ptr(Node *Control) { this->ControlPtr = Control; } |
| 998 | |
| 999 | void set_effect_ptr(Node *Effect) { this->EffectPtr = Effect; } |
| 1000 | |
| 1001 | private: |
| 1002 | wasm::ModuleEnv *Module; |
| 1003 | Node *ControlPtr; |
| 1004 | Node *EffectPtr; |
| 1005 | |
| 1006 | class Cfg *Func; |
| 1007 | GlobalContext *Ctx; |
| 1008 | |
| 1009 | SizeT NextArg = 0; |
| 1010 | |
| 1011 | CfgUnorderedMap<Operand *, InstPhi *> PhiMap; |
| 1012 | CfgUnorderedMap<Operand *, CfgNode *> DefNodeMap; |
| 1013 | |
| 1014 | InstPhi *getDefiningInst(Operand *Op) const { |
| 1015 | const auto &Iter = PhiMap.find(Op); |
| 1016 | if (Iter == PhiMap.end()) { |
| 1017 | return nullptr; |
| 1018 | } |
| 1019 | return Iter->second; |
| 1020 | } |
| 1021 | |
| 1022 | void setDefiningInst(Operand *Op, InstPhi *Phi) { |
| 1023 | LOG(out << "\n== setDefiningInst(" << Op << ", " << Phi << ") ==\n"); |
| 1024 | PhiMap.emplace(Op, Phi); |
| 1025 | } |
| 1026 | |
| 1027 | Ice::Variable *makeVariable(Ice::Type Type) { |
| 1028 | return makeVariable(Type, Control()); |
| 1029 | } |
| 1030 | |
| 1031 | Ice::Variable *makeVariable(Ice::Type Type, CfgNode *DefNode) { |
| 1032 | auto *Var = Func->makeVariable(Type); |
| 1033 | DefNodeMap.emplace(Var, DefNode); |
| 1034 | return Var; |
| 1035 | } |
| 1036 | |
| 1037 | CfgNode *getDefNode(Operand *Op) const { |
| 1038 | const auto &Iter = DefNodeMap.find(Op); |
| 1039 | if (Iter == DefNodeMap.end()) { |
| 1040 | return nullptr; |
| 1041 | } |
| 1042 | return Iter->second; |
| 1043 | } |
| 1044 | |
| 1045 | template <typename F = std::function<void(Ostream &)>> void log(F Fn) const { |
| 1046 | if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) { |
| 1047 | Fn(Ctx->getStrDump()); |
| 1048 | Ctx->getStrDump().flush(); |
| 1049 | } |
| 1050 | } |
| 1051 | }; |
| 1052 | |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1053 | std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1054 | FunctionBody &Body) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1055 | OstreamLocker L1(Ctx); |
| 1056 | auto Func = Cfg::create(Ctx, getNextSequenceNumber()); |
| 1057 | Ice::CfgLocalAllocatorScope L2(Func.get()); |
| 1058 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1059 | // TODO(eholk): parse the function signature... |
| 1060 | |
| 1061 | Func->setEntryNode(Func->makeNode()); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1062 | |
| 1063 | IceBuilder Builder(Func.get()); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1064 | SR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder, Body); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1065 | |
| 1066 | LOG(out << getFlags().getDefaultGlobalPrefix() << "\n"); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1067 | Decoder.Decode(); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1068 | |
| 1069 | // We don't always know where the incoming branches are in phi nodes, so this |
| 1070 | // function finds them. |
| 1071 | Func->fixPhiNodes(); |
| 1072 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1073 | Func->computeInOutEdges(); |
| 1074 | |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1075 | return Func; |
| 1076 | } |
| 1077 | |
| 1078 | WasmTranslator::WasmTranslator(GlobalContext *Ctx) |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1079 | : Translator(Ctx), Buffer(new uint8_t[24 << 10]), BufferSize(24 << 10) { |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1080 | // TODO(eholk): compute the correct buffer size. This uses 24k by default, |
| 1081 | // which has been big enough for testing but is not a general solution. |
| 1082 | } |
| 1083 | |
| 1084 | void WasmTranslator::translate( |
| 1085 | const std::string &IRFilename, |
| 1086 | std::unique_ptr<llvm::DataStreamer> InputStream) { |
| 1087 | LOG(out << "Initializing v8/wasm stuff..." |
| 1088 | << "\n"); |
| 1089 | Zone Zone; |
| 1090 | ZoneScope _(&Zone); |
| 1091 | |
| 1092 | SizeT BytesRead = InputStream->GetBytes(Buffer.get(), BufferSize); |
| 1093 | LOG(out << "Read " << BytesRead << " bytes" |
| 1094 | << "\n"); |
| 1095 | |
| 1096 | LOG(out << "Decoding module " << IRFilename << "\n"); |
| 1097 | |
| 1098 | constexpr v8::internal::Isolate *NoIsolate = nullptr; |
| 1099 | auto Result = DecodeWasmModule(NoIsolate, &Zone, Buffer.get(), |
| 1100 | Buffer.get() + BytesRead, false, kWasmOrigin); |
| 1101 | |
| 1102 | auto Module = Result.val; |
| 1103 | |
| 1104 | LOG(out << "Module info:" |
| 1105 | << "\n"); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1106 | LOG(out << " min_mem_pages: " << Module->min_mem_pages << "\n"); |
| 1107 | LOG(out << " max_mem_pages: " << Module->max_mem_pages << "\n"); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1108 | LOG(out << " number of globals: " << Module->globals.size() << "\n"); |
| 1109 | LOG(out << " number of signatures: " << Module->signatures.size() |
| 1110 | << "\n"); |
| 1111 | LOG(out << " number of functions: " << Module->functions.size() << "\n"); |
| 1112 | LOG(out << " number of data_segments: " << Module->data_segments.size() |
| 1113 | << "\n"); |
| 1114 | LOG(out << " function table size: " << Module->function_table.size() |
| 1115 | << "\n"); |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1116 | LOG(out << " import table size: " << Module->import_table.size() |
| 1117 | << "\n"); |
| 1118 | LOG(out << " export table size: " << Module->export_table.size() |
| 1119 | << "\n"); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1120 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1121 | LOG(out << "\n" |
| 1122 | << "Data segment information:" |
| 1123 | << "\n"); |
| 1124 | uint32_t Id = 0; |
| 1125 | for (const auto Seg : Module->data_segments) { |
| 1126 | LOG(out << Id << ": (" << Seg.source_offset << ", " << Seg.source_size |
| 1127 | << ") => " << Seg.dest_addr); |
| 1128 | if (Seg.init) { |
| 1129 | LOG(out << " init\n"); |
| 1130 | } else { |
| 1131 | LOG(out << "\n"); |
| 1132 | } |
| 1133 | Id++; |
| 1134 | } |
| 1135 | |
| 1136 | LOG(out << "\n" |
| 1137 | << "Import information:" |
| 1138 | << "\n"); |
| 1139 | for (const auto Import : Module->import_table) { |
| 1140 | auto ModuleName = toStdString( |
| 1141 | Module->GetName(Import.module_name_offset, Import.module_name_length)); |
| 1142 | auto FnName = toStdString(Module->GetName(Import.function_name_offset, |
| 1143 | Import.function_name_length)); |
| 1144 | LOG(out << " " << Import.sig_index << ": " << ModuleName << "::" << FnName |
| 1145 | << "\n"); |
| 1146 | } |
| 1147 | |
| 1148 | LOG(out << "\n" |
| 1149 | << "Export information:" |
| 1150 | << "\n"); |
| 1151 | for (const auto Export : Module->export_table) { |
| 1152 | LOG(out << " " << Export.func_index << ": " |
| 1153 | << toStdString( |
| 1154 | Module->GetName(Export.name_offset, Export.name_length)) |
| 1155 | << " (" << Export.name_offset << ", " << Export.name_length << ")"); |
| 1156 | LOG(out << "\n"); |
| 1157 | } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1158 | |
| 1159 | LOG(out << "\n" |
| 1160 | << "Function information:" |
| 1161 | << "\n"); |
| 1162 | for (const auto F : Module->functions) { |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1163 | LOG(out << " " << F.func_index << ": " |
| 1164 | << toStdString(Module->GetName(F.name_offset, F.name_length)) |
| 1165 | << " (" << F.name_offset << ", " << F.name_length << ")"); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1166 | if (F.exported) |
| 1167 | LOG(out << " export"); |
| 1168 | if (F.external) |
| 1169 | LOG(out << " extern"); |
| 1170 | LOG(out << "\n"); |
| 1171 | } |
| 1172 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1173 | LOG(out << "\n" |
| 1174 | << "Indirect table:" |
| 1175 | << "\n"); |
| 1176 | for (uint32_t F : Module->function_table) { |
| 1177 | LOG(out << " " << F << ": " << getFunctionName(Module, F) << "\n"); |
| 1178 | } |
| 1179 | |
| 1180 | ModuleEnv ModuleEnv; |
| 1181 | ModuleEnv.module = Module; |
| 1182 | |
| 1183 | FunctionBody Body; |
| 1184 | Body.module = &ModuleEnv; |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1185 | |
| 1186 | LOG(out << "Translating " << IRFilename << "\n"); |
| 1187 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1188 | { |
| 1189 | unique_ptr<VariableDeclarationList> Globals = |
| 1190 | makeUnique<VariableDeclarationList>(); |
| 1191 | |
| 1192 | // Global variables, etc go here. |
| 1193 | auto *WasmMemory = VariableDeclaration::createExternal(Globals.get()); |
| 1194 | WasmMemory->setName(Ctx->getGlobalString("WASM_MEMORY")); |
| 1195 | |
| 1196 | // Fill in the segments |
| 1197 | SizeT WritePtr = 0; |
| 1198 | for (const auto Seg : Module->data_segments) { |
| 1199 | // fill in gaps with zero. |
| 1200 | if (Seg.dest_addr > WritePtr) { |
| 1201 | WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create( |
| 1202 | Globals.get(), Seg.dest_addr - WritePtr)); |
| 1203 | WritePtr = Seg.dest_addr; |
| 1204 | } |
| 1205 | |
| 1206 | // Add the data |
| 1207 | WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create( |
| 1208 | Globals.get(), reinterpret_cast<const char *>(Module->module_start) + |
| 1209 | Seg.source_offset, |
| 1210 | Seg.source_size)); |
| 1211 | |
| 1212 | WritePtr += Seg.source_size; |
| 1213 | } |
| 1214 | |
| 1215 | // Pad the rest with zeros |
| 1216 | SizeT DataSize = Module->min_mem_pages * (64 << 10); |
| 1217 | if (WritePtr < DataSize) { |
| 1218 | WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create( |
| 1219 | Globals.get(), DataSize - WritePtr)); |
| 1220 | } |
| 1221 | |
| 1222 | WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create( |
| 1223 | Globals.get(), Module->min_mem_pages * (64 << 10))); |
| 1224 | |
| 1225 | Globals->push_back(WasmMemory); |
| 1226 | |
| 1227 | lowerGlobals(std::move(Globals)); |
| 1228 | } |
| 1229 | |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1230 | // Translate each function. |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1231 | for (const auto Fn : Module->functions) { |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1232 | const auto FnName = getFunctionName(Module, Fn.func_index); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1233 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1234 | LOG(out << " " << Fn.func_index << ": " << FnName << "..."); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1235 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame^] | 1236 | Body.sig = Fn.sig; |
| 1237 | Body.base = Buffer.get(); |
| 1238 | Body.start = Buffer.get() + Fn.code_start_offset; |
| 1239 | Body.end = Buffer.get() + Fn.code_end_offset; |
| 1240 | |
| 1241 | auto Func = translateFunction(&Zone, Body); |
| 1242 | Func->setFunctionName(Ctx->getGlobalString(FnName)); |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 1243 | |
| 1244 | Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func))); |
| 1245 | LOG(out << "done.\n"); |
| 1246 | } |
| 1247 | |
| 1248 | return; |
| 1249 | } |
John Porto | 681f90f | 2016-04-05 06:20:50 -0700 | [diff] [blame] | 1250 | |
| 1251 | #endif // ALLOW_WASM |