Index: src/WasmTranslator.cpp |
diff --git a/src/WasmTranslator.cpp b/src/WasmTranslator.cpp |
index 7c462d9b1b06c1de46c4150b8a4fe8ae4858281b..14b0607cac63ad5bc5e8555c103f8ca9163f9a40 100644 |
--- a/src/WasmTranslator.cpp |
+++ b/src/WasmTranslator.cpp |
@@ -229,10 +229,18 @@ bool isComparison(wasm::WasmOpcode Opcode) { |
case kExprI64GtS: |
case kExprI32GtU: |
case kExprI64GtU: |
+ case kExprF32Eq: |
+ case kExprF64Eq: |
case kExprF32Ne: |
case kExprF64Ne: |
case kExprF32Le: |
case kExprF64Le: |
+ case kExprF32Lt: |
+ case kExprF64Lt: |
+ case kExprF32Ge: |
+ case kExprF64Ge: |
+ case kExprF32Gt: |
+ case kExprF64Gt: |
case kExprI32LeS: |
case kExprI64LeS: |
case kExprI32GeU: |
@@ -324,7 +332,7 @@ public: |
// TODO(eholk): find a better way besides multiplying by some arbitrary |
// constant. |
- auto *Phi = InstPhi::create(Func, Count * 10, Dest); |
+ auto *Phi = InstPhi::create(Func, Count * 200, Dest); |
for (uint32_t i = 0; i < Count; ++i) { |
auto *Op = Vals[i].toOperand(); |
assert(Op); |
@@ -393,16 +401,36 @@ public: |
Control()->appendInst( |
InstArithmetic::create(Func, InstArithmetic::Sub, Dest, Left, Right)); |
break; |
+ case kExprF32Sub: |
+ case kExprF64Sub: |
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Fsub, |
+ Dest, Left, Right)); |
+ break; |
case kExprI32Mul: |
case kExprI64Mul: |
Control()->appendInst( |
InstArithmetic::create(Func, InstArithmetic::Mul, Dest, Left, Right)); |
break; |
+ case kExprF32Mul: |
+ case kExprF64Mul: |
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Fmul, |
+ Dest, Left, Right)); |
+ break; |
+ case kExprI32DivS: |
+ case kExprI64DivS: |
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Sdiv, |
+ Dest, Left, Right)); |
+ break; |
case kExprI32DivU: |
case kExprI64DivU: |
Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Udiv, |
Dest, Left, Right)); |
break; |
+ case kExprF32Div: |
+ case kExprF64Div: |
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Fdiv, |
+ Dest, Left, Right)); |
+ break; |
case kExprI32RemU: |
case kExprI64RemU: |
Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Urem, |
@@ -428,30 +456,63 @@ public: |
Control()->appendInst( |
InstArithmetic::create(Func, InstArithmetic::Shl, Dest, Left, Right)); |
break; |
- case kExprI32Rol: { |
+ case kExprI32Rol: |
+ case kExprI64Rol: { |
// TODO(eholk): add rotate as an ICE instruction to make it easier to take |
// advantage of hardware support. |
- // TODO(eholk): don't hardcode so many numbers. |
- auto *Masked = makeVariable(IceType_i32); |
- auto *Bottom = makeVariable(IceType_i32); |
- auto *Top = makeVariable(IceType_i32); |
- Control()->appendInst(InstArithmetic::create( |
- Func, InstArithmetic::And, Masked, Right, Ctx->getConstantInt32(31))); |
+ const auto DestTy = Left.toOperand()->getType(); |
+ const SizeT BitCount = typeWidthInBytes(DestTy) * 8; |
+ |
+ auto *Masked = makeVariable(DestTy); |
+ auto *Bottom = makeVariable(DestTy); |
+ auto *Top = makeVariable(DestTy); |
+ Control()->appendInst( |
+ InstArithmetic::create(Func, InstArithmetic::And, Masked, Right, |
+ Ctx->getConstantInt(DestTy, BitCount - 1))); |
Control()->appendInst( |
InstArithmetic::create(Func, InstArithmetic::Shl, Top, Left, Masked)); |
- auto *RotShift = makeVariable(IceType_i32); |
+ auto *RotShift = makeVariable(DestTy); |
+ Control()->appendInst(InstArithmetic::create( |
+ Func, InstArithmetic::Sub, RotShift, |
+ Ctx->getConstantInt(DestTy, BitCount), Masked)); |
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Lshr, |
+ Bottom, Left, RotShift)); |
+ Control()->appendInst( |
+ InstArithmetic::create(Func, InstArithmetic::Or, Dest, Top, Bottom)); |
+ break; |
+ } |
+ case kExprI32Ror: |
+ case kExprI64Ror: { |
+ // TODO(eholk): add rotate as an ICE instruction to make it easier to take |
+ // advantage of hardware support. |
+ |
+ const auto DestTy = Left.toOperand()->getType(); |
+ const SizeT BitCount = typeWidthInBytes(DestTy) * 8; |
+ |
+ auto *Masked = makeVariable(DestTy); |
+ auto *Bottom = makeVariable(DestTy); |
+ auto *Top = makeVariable(DestTy); |
Control()->appendInst( |
- InstArithmetic::create(Func, InstArithmetic::Sub, RotShift, |
- Ctx->getConstantInt32(32), Masked)); |
+ InstArithmetic::create(Func, InstArithmetic::And, Masked, Right, |
+ Ctx->getConstantInt(DestTy, BitCount - 1))); |
Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Lshr, |
- Bottom, Left, Masked)); |
+ Top, Left, Masked)); |
+ auto *RotShift = makeVariable(DestTy); |
+ Control()->appendInst(InstArithmetic::create( |
+ Func, InstArithmetic::Sub, RotShift, |
+ Ctx->getConstantInt(DestTy, BitCount), Masked)); |
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Shl, |
+ Bottom, Left, RotShift)); |
Control()->appendInst( |
InstArithmetic::create(Func, InstArithmetic::Or, Dest, Top, Bottom)); |
break; |
} |
case kExprI32ShrU: |
case kExprI64ShrU: |
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Lshr, |
+ Dest, Left, Right)); |
+ break; |
case kExprI32ShrS: |
case kExprI64ShrS: |
Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Ashr, |
@@ -532,6 +593,7 @@ public: |
InstIcmp::create(Func, InstIcmp::Sge, TmpDest, Left, Right)); |
Control()->appendInst( |
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); |
+ break; |
} |
case kExprI32GtS: |
case kExprI64GtS: { |
@@ -551,6 +613,15 @@ public: |
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); |
break; |
} |
+ case kExprF32Eq: |
+ case kExprF64Eq: { |
+ auto *TmpDest = makeVariable(IceType_i1); |
+ Control()->appendInst( |
+ InstFcmp::create(Func, InstFcmp::Ueq, TmpDest, Left, Right)); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); |
+ break; |
+ } |
case kExprF32Ne: |
case kExprF64Ne: { |
auto *TmpDest = makeVariable(IceType_i1); |
@@ -569,6 +640,33 @@ public: |
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); |
break; |
} |
+ case kExprF32Lt: |
+ case kExprF64Lt: { |
+ auto *TmpDest = makeVariable(IceType_i1); |
+ Control()->appendInst( |
+ InstFcmp::create(Func, InstFcmp::Ult, TmpDest, Left, Right)); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); |
+ break; |
+ } |
+ case kExprF32Ge: |
+ case kExprF64Ge: { |
+ auto *TmpDest = makeVariable(IceType_i1); |
+ Control()->appendInst( |
+ InstFcmp::create(Func, InstFcmp::Uge, TmpDest, Left, Right)); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); |
+ break; |
+ } |
+ case kExprF32Gt: |
+ case kExprF64Gt: { |
+ auto *TmpDest = makeVariable(IceType_i1); |
+ Control()->appendInst( |
+ InstFcmp::create(Func, InstFcmp::Ugt, TmpDest, Left, Right)); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); |
+ break; |
+ } |
default: |
LOG(out << "Unknown binop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); |
llvm::report_fatal_error("Uncovered or invalid binop."); |
@@ -598,6 +696,20 @@ public: |
Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp)); |
break; |
} |
+ case kExprI32Ctz: { |
+ Dest = makeVariable(IceType_i32); |
+ const auto FnName = Ctx->getGlobalString("llvm.cttz.i32"); |
+ bool BadInstrinsic = false; |
+ const auto *Info = Ctx->getIntrinsicsInfo().find(FnName, BadInstrinsic); |
+ assert(!BadInstrinsic); |
+ assert(Info); |
+ |
+ auto *Call = InstIntrinsicCall::create( |
+ Func, 1, Dest, Ctx->getConstantExternSym(FnName), Info->Info); |
+ Call->addArg(Input); |
+ Control()->appendInst(Call); |
+ break; |
+ } |
case kExprF32Neg: { |
Dest = makeVariable(IceType_f32); |
Control()->appendInst(InstArithmetic::create( |
@@ -610,6 +722,56 @@ public: |
Func, InstArithmetic::Fsub, Dest, Ctx->getConstantDouble(0), Input)); |
break; |
} |
+ case kExprF32Abs: { |
+ Dest = makeVariable(IceType_f32); |
+ const auto FnName = Ctx->getGlobalString("llvm.fabs.f32"); |
+ bool BadInstrinsic = false; |
+ const auto *Info = Ctx->getIntrinsicsInfo().find(FnName, BadInstrinsic); |
+ assert(!BadInstrinsic); |
+ assert(Info); |
+ |
+ auto *Call = InstIntrinsicCall::create( |
+ Func, 1, Dest, Ctx->getConstantExternSym(FnName), Info->Info); |
+ Call->addArg(Input); |
+ Control()->appendInst(Call); |
+ break; |
+ } |
+ case kExprF64Abs: { |
+ Dest = makeVariable(IceType_f64); |
+ const auto FnName = Ctx->getGlobalString("llvm.fabs.f64"); |
+ bool BadInstrinsic = false; |
+ const auto *Info = Ctx->getIntrinsicsInfo().find(FnName, BadInstrinsic); |
+ assert(!BadInstrinsic); |
+ assert(Info); |
+ |
+ auto *Call = InstIntrinsicCall::create( |
+ Func, 1, Dest, Ctx->getConstantExternSym(FnName), Info->Info); |
+ Call->addArg(Input); |
+ Control()->appendInst(Call); |
+ break; |
+ } |
+ case kExprF32Floor: { |
+ Dest = makeVariable(IceType_f64); |
+ const auto FnName = Ctx->getGlobalString("_ZN3env5floorEf"); |
+ constexpr bool HasTailCall = false; |
+ |
+ auto *Call = InstCall::create( |
+ Func, 1, Dest, Ctx->getConstantExternSym(FnName), HasTailCall); |
+ Call->addArg(Input); |
+ Control()->appendInst(Call); |
+ break; |
+ } |
+ case kExprF64Floor: { |
+ Dest = makeVariable(IceType_f64); |
+ const auto FnName = Ctx->getGlobalString("_ZN3env5floorEd"); |
+ constexpr bool HasTailCall = false; |
+ |
+ auto *Call = InstCall::create( |
+ Func, 1, Dest, Ctx->getConstantExternSym(FnName), HasTailCall); |
+ Call->addArg(Input); |
+ Control()->appendInst(Call); |
+ break; |
+ } |
case kExprI64UConvertI32: |
Dest = makeVariable(IceType_i64); |
Control()->appendInst( |
@@ -620,6 +782,41 @@ public: |
Control()->appendInst( |
InstCast::create(Func, InstCast::Sext, Dest, Input)); |
break; |
+ case kExprI32SConvertF32: |
+ Dest = makeVariable(IceType_i32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Fptosi, Dest, Input)); |
+ break; |
+ case kExprI32UConvertF32: |
+ Dest = makeVariable(IceType_i32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Fptoui, Dest, Input)); |
+ break; |
+ case kExprI32SConvertF64: |
+ Dest = makeVariable(IceType_i32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Fptosi, Dest, Input)); |
+ break; |
+ case kExprI32UConvertF64: |
+ Dest = makeVariable(IceType_i32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Fptoui, Dest, Input)); |
+ break; |
+ case kExprI32ReinterpretF32: |
+ Dest = makeVariable(IceType_i32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Bitcast, Dest, Input)); |
+ break; |
+ case kExprI64ReinterpretF64: |
+ Dest = makeVariable(IceType_i64); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Bitcast, Dest, Input)); |
+ break; |
+ case kExprF64ReinterpretI64: |
+ Dest = makeVariable(IceType_f64); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Bitcast, Dest, Input)); |
+ break; |
case kExprI32ConvertI64: |
Dest = makeVariable(IceType_i32); |
Control()->appendInst( |
@@ -630,6 +827,36 @@ public: |
Control()->appendInst( |
InstCast::create(Func, InstCast::Sitofp, Dest, Input)); |
break; |
+ case kExprF64UConvertI32: |
+ Dest = makeVariable(IceType_f64); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Uitofp, Dest, Input)); |
+ break; |
+ case kExprF64ConvertF32: |
+ Dest = makeVariable(IceType_f64); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Fpext, Dest, Input)); |
+ break; |
+ case kExprF32SConvertI32: |
+ Dest = makeVariable(IceType_f32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Sitofp, Dest, Input)); |
+ break; |
+ case kExprF32UConvertI32: |
+ Dest = makeVariable(IceType_f32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Uitofp, Dest, Input)); |
+ break; |
+ case kExprF32ReinterpretI32: |
+ Dest = makeVariable(IceType_f32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Bitcast, Dest, Input)); |
+ break; |
+ case kExprF32ConvertF64: |
+ Dest = makeVariable(IceType_f32); |
+ Control()->appendInst( |
+ InstCast::create(Func, InstCast::Fptrunc, Dest, Input)); |
+ break; |
default: |
LOG(out << "Unknown unop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); |
llvm::report_fatal_error("Uncovered or invalid unop."); |
@@ -953,7 +1180,8 @@ public: |
Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index, |
uint32_t Offset) { |
- LOG(out << "LoadMem(" << Index << "[" << Offset << "]) = "); |
+ LOG(out << "LoadMem." << toIceType(MemType) << "(" << Index << "[" << Offset |
+ << "]) = "); |
auto *RealAddr = sanitizeAddress(Index, Offset); |
@@ -988,7 +1216,8 @@ public: |
return OperandNode(Result); |
} |
void StoreMem(MachineType Type, Node Index, uint32_t Offset, Node Val) { |
- LOG(out << "StoreMem(" << Index << "[" << Offset << "] = " << Val << ")" |
+ LOG(out << "StoreMem." << toIceType(Type) << "(" << Index << "[" << Offset |
+ << "] = " << Val << ")" |
<< "\n"); |
auto *RealAddr = sanitizeAddress(Index, Offset); |
@@ -1101,11 +1330,13 @@ std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, |
return Func; |
} |
+// TODO(eholk): compute the correct buffer size. This uses 256k by default, |
+// which has been big enough for testing but is not a general solution. |
+constexpr SizeT BUFFER_SIZE = 256 << 10; |
+ |
WasmTranslator::WasmTranslator(GlobalContext *Ctx) |
- : Translator(Ctx), Buffer(new uint8_t[24 << 10]), BufferSize(24 << 10) { |
- // TODO(eholk): compute the correct buffer size. This uses 24k by default, |
- // which has been big enough for testing but is not a general solution. |
-} |
+ : Translator(Ctx), Buffer(new uint8_t[BUFFER_SIZE]), |
+ BufferSize(BUFFER_SIZE) {} |
void WasmTranslator::translate( |
const std::string &IRFilename, |
@@ -1118,6 +1349,7 @@ void WasmTranslator::translate( |
SizeT BytesRead = InputStream->GetBytes(Buffer.get(), BufferSize); |
LOG(out << "Read " << BytesRead << " bytes" |
<< "\n"); |
+ assert(BytesRead < BufferSize); |
LOG(out << "Decoding module " << IRFilename << "\n"); |