#include <asm_v_wasm.h>
#include <ir/literal-utils.h>
#include <pass.h>
#include <wasm-builder.h>
#include <wasm.h>
namespace wasm {
static const int NUM_PARAMS = 16;
static Expression* toABI(Expression* value, Module* module) {
Builder builder(*module);
switch (value->type.getBasic()) {
case Type::i32: {
value = builder.makeUnary(ExtendUInt32, value);
break;
}
case Type::i64: {
break;
}
case Type::f32: {
value = builder.makeUnary(ExtendUInt32,
builder.makeUnary(ReinterpretFloat32, value));
break;
}
case Type::f64: {
value = builder.makeUnary(ReinterpretFloat64, value);
break;
}
case Type::v128: {
WASM_UNREACHABLE("v128 not implemented yet");
}
case Type::funcref:
case Type::externref:
case Type::exnref:
case Type::anyref:
case Type::eqref:
case Type::i31ref: {
WASM_UNREACHABLE("reference types cannot be converted to i64");
}
case Type::none: {
value =
builder.makeSequence(value, LiteralUtils::makeZero(Type::i64, *module));
break;
}
case Type::unreachable: {
break;
}
}
return value;
}
static Expression* fromABI(Expression* value, Type type, Module* module) {
Builder builder(*module);
switch (type.getBasic()) {
case Type::i32: {
value = builder.makeUnary(WrapInt64, value);
break;
}
case Type::i64: {
break;
}
case Type::f32: {
value = builder.makeUnary(ReinterpretInt32,
builder.makeUnary(WrapInt64, value));
break;
}
case Type::f64: {
value = builder.makeUnary(ReinterpretInt64, value);
break;
}
case Type::v128: {
WASM_UNREACHABLE("v128 not implemented yet");
}
case Type::funcref:
case Type::externref:
case Type::exnref:
case Type::anyref:
case Type::eqref:
case Type::i31ref: {
WASM_UNREACHABLE("reference types cannot be converted from i64");
}
case Type::none: {
value = builder.makeDrop(value);
}
case Type::unreachable: {
break;
}
}
return value;
}
struct ParallelFuncCastEmulation
: public WalkerPass<PostWalker<ParallelFuncCastEmulation>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new ParallelFuncCastEmulation(ABIType); }
ParallelFuncCastEmulation(Signature ABIType) : ABIType(ABIType) {}
void visitCallIndirect(CallIndirect* curr) {
if (curr->operands.size() > NUM_PARAMS) {
Fatal() << "FuncCastEmulation::NUM_PARAMS needs to be at least "
<< curr->operands.size();
}
for (Expression*& operand : curr->operands) {
operand = toABI(operand, getModule());
}
while (curr->operands.size() < NUM_PARAMS) {
curr->operands.push_back(LiteralUtils::makeZero(Type::i64, *getModule()));
}
curr->sig = ABIType;
auto oldType = curr->type;
curr->type = Type::i64;
curr->finalize(); replaceCurrent(fromABI(curr, oldType, getModule()));
}
private:
Signature ABIType;
};
struct FuncCastEmulation : public Pass {
void run(PassRunner* runner, Module* module) override {
Signature ABIType(Type(std::vector<Type>(NUM_PARAMS, Type::i64)),
Type::i64);
std::unordered_map<Name, Name> funcThunks;
for (auto& segment : module->table.segments) {
for (auto& name : segment.data) {
auto iter = funcThunks.find(name);
if (iter == funcThunks.end()) {
auto thunk = makeThunk(name, module);
funcThunks[name] = thunk;
name = thunk;
} else {
name = iter->second;
}
}
}
ParallelFuncCastEmulation(ABIType).run(runner, module);
}
private:
Name makeThunk(Name name, Module* module) {
Name thunk = std::string("byn$fpcast-emu$") + name.str;
if (module->getFunctionOrNull(thunk)) {
Fatal() << "FuncCastEmulation::makeThunk seems a thunk name already in "
"use. Was the pass already run on this code?";
}
auto* func = module->getFunction(name);
Type type = func->sig.results;
Builder builder(*module);
std::vector<Expression*> callOperands;
Index i = 0;
for (const auto& param : func->sig.params) {
callOperands.push_back(
fromABI(builder.makeLocalGet(i++, Type::i64), param, module));
}
auto* call = builder.makeCall(name, callOperands, type);
std::vector<Type> thunkParams;
for (Index i = 0; i < NUM_PARAMS; i++) {
thunkParams.push_back(Type::i64);
}
auto* thunkFunc =
builder.makeFunction(thunk,
Signature(Type(thunkParams), Type::i64),
{}, toABI(call, module));
module->addFunction(thunkFunc);
return thunk;
}
};
Pass* createFuncCastEmulationPass() { return new FuncCastEmulation(); }
}