diff options
author | Alon Zakai <alonzakai@gmail.com> | 2015-11-18 17:26:02 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2015-11-18 17:26:02 -0800 |
commit | 7749b84bfaf5f7d95d22332b520ea541c6f9ae80 (patch) | |
tree | 093c097568e80ed522ed7911d048d06aa2a437b1 | |
parent | 8936d78d84473b258aa1b0245d2f0f22c79643f4 (diff) | |
download | binaryen-7749b84bfaf5f7d95d22332b520ea541c6f9ae80.tar.gz binaryen-7749b84bfaf5f7d95d22332b520ea541c6f9ae80.tar.bz2 binaryen-7749b84bfaf5f7d95d22332b520ea541c6f9ae80.zip |
handle overloading of Math.abs
-rw-r--r-- | src/asm2wasm.h | 111 | ||||
-rw-r--r-- | test/unit.asm.js | 7 |
2 files changed, 104 insertions, 14 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 4eb119ae0..2d286a610 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -36,6 +36,7 @@ IString GLOBAL("global"), NAN_("NaN"), INFINITY_("Infinity"), F64_TO_INT("f64-to-int"), GLOBAL_MATH("global.Math"), ABS("abs"), + I32_TEMP("asm2wasm_i32_temp"), DEBUGGER("debugger"); @@ -124,9 +125,12 @@ private: }; std::map<IString, View> views; // name (e.g. HEAP8) => view info - IString Math_imul; // imported name of Math.imul - IString Math_clz32; // imported name of Math.imul - IString Math_fround; // imported name of Math.fround + + // Imported names of Math.* + IString Math_imul; + IString Math_clz32; + IString Math_fround; + IString Math_abs; // function types. we fill in this information as we see // uses, in the first pass @@ -371,16 +375,39 @@ private: else if (call->is<CallIndirect>()) call->type = type; } - FunctionType* getBuiltinFunctionType(Name module, Name base) { + FunctionType* getBuiltinFunctionType(Name module, Name base, ExpressionList* operands = nullptr) { if (module == GLOBAL_MATH) { - if (base == ABS /* XXX, this should be overloaded */) { - static FunctionType* builtin = nullptr; - if (!builtin) { - builtin = new FunctionType(); - builtin->params.push_back(f64); - builtin->result = f64; + if (base == ABS) { + assert(operands && operands->size() == 1); + WasmType type = (*operands)[0]->type; + if (type == i32) { + static FunctionType* builtin = nullptr; + if (!builtin) { + builtin = new FunctionType(); + builtin->params.push_back(i32); + builtin->result = i32; + } + return builtin; + } + if (type == f32) { + static FunctionType* builtin = nullptr; + if (!builtin) { + builtin = new FunctionType(); + builtin->params.push_back(f32); + builtin->result = f32; + } + return builtin; } - return builtin; + if (type == f64) { + static FunctionType* builtin = nullptr; + if (!builtin) { + builtin = new FunctionType(); + builtin->params.push_back(f64); + builtin->result = f64; + } + return builtin; + } + } } return nullptr; @@ -416,6 +443,10 @@ void Asm2WasmBuilder::processAsm(Ref ast) { assert(Math_fround.isNull()); Math_fround = name; return; + } else if (imported[2] == ABS) { + assert(Math_abs.isNull()); + Math_abs = name; + return; } } std::string fullName = module[1][1]->getCString(); @@ -646,6 +677,15 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { start++; } + bool addedI32Temp = false; + auto ensureI32Temp = [&]() { + if (addedI32Temp) return; + addedI32Temp = true; + function->locals.emplace_back(I32_TEMP, i32); + functionVariables.insert(I32_TEMP); + asmData.addVar(I32_TEMP, ASM_INT); + }; + bool seenReturn = false; // function->result is updated if we see a return bool needTopmost = false; // we label the topmost b lock if we need one for a return // processors @@ -971,15 +1011,58 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { ret->type = f32; return ret; } + if (name == Math_abs) { + // overloaded on type: i32, f32 or f64 + Expression* value = process(ast[2][0]); + if (value->type == i32) { + // No wasm support, so use a temp local + ensureI32Temp(); + auto set = allocator.alloc<SetLocal>(); + set->name = I32_TEMP; + set->value = value; + set->type = i32; + auto get = [&]() { + auto ret = allocator.alloc<GetLocal>(); + ret->name = I32_TEMP; + ret->type = i32; + return ret; + }; + auto isNegative = allocator.alloc<Compare>(); + isNegative->op = LtS; + isNegative->inputType = i32; + isNegative->left = get(); + isNegative->right = allocator.alloc<Const>()->set(0); + auto block = allocator.alloc<Block>(); + block->list.push_back(set); + auto flip = allocator.alloc<Binary>(); + flip->op = Sub; + flip->left = allocator.alloc<Const>()->set(0); + flip->right = get(); + flip->type = i32; + auto select = allocator.alloc<Select>(); + select->condition = isNegative; + select->ifTrue = flip; + select->ifFalse = get(); + select->type = i32; + block->list.push_back(set); + block->type = i32; + return block; + } else if (value->type == f32 || value->type == f64) { + auto ret = allocator.alloc<Unary>(); + ret->op = Abs; + ret->value = value; + ret->type = value->type; + return ret; + } else { + abort(); + } + } Call* ret; if (wasm.importsMap.find(name) != wasm.importsMap.end()) { Ref parent = astStackHelper.getParent(); WasmType type = !!parent ? detectWasmType(parent, &asmData) : none; ret = allocator.alloc<CallImport>(); noteImportedFunctionCall(ast, type, &asmData); - Import* import = wasm.importsMap[name]; - auto builtin = getBuiltinFunctionType(import->module, import->base); - if (builtin) ret->type = builtin->result; } else { ret = allocator.alloc<Call>(); } diff --git a/test/unit.asm.js b/test/unit.asm.js index 7575dfead..ed52e515b 100644 --- a/test/unit.asm.js +++ b/test/unit.asm.js @@ -5,6 +5,7 @@ function () { var Int = 0; var Double = 0.0; var Math_fround = global.Math.fround; + var Math_abs = global.Math.abs; function big_negative() { var temp = 0.0; @@ -78,6 +79,12 @@ function () { function negZero() { return +-0; } + function abs() { + var x = 0, y = 0.0, z = Math_fround(0); + x = Math_abs(0) | 0; + y = +Math_abs(0.0); + z = Math_fround(Math_abs(Math_fround(0))); + } function z() { } |