Subzero WASM: avoid needless comparisons, add bounds check flag option
Introduces a new BooleanVariable type which represents zero-extended
variables generated from an i1, saving a pointer to the original
i1. The Wasm frontend uses this to avoid comparing against 0 if
possible when translating branches. This led to about a 12%
improvement on the bzip2 spec benchmark.
This change also adds the -wasm-disable-bounds-check command line
option which omits bounds checking code.
BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4369
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/1961583002 .
diff --git a/src/WasmTranslator.cpp b/src/WasmTranslator.cpp
index 792e134..cb6da00 100644
--- a/src/WasmTranslator.cpp
+++ b/src/WasmTranslator.cpp
@@ -49,7 +49,6 @@
using namespace std;
using namespace Ice;
-using namespace v8;
using namespace v8::internal;
using namespace v8::internal::wasm;
using v8::internal::wasm::DecodeWasmModule;
@@ -255,6 +254,7 @@
class IceBuilder {
using Node = OperandNode;
+ using Variable = Ice::Variable;
IceBuilder() = delete;
IceBuilder(const IceBuilder &) = delete;
@@ -393,8 +393,14 @@
Node Binop(wasm::WasmOpcode Opcode, Node Left, Node Right) {
LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left
<< ", " << Right << ") = ");
- auto *Dest = makeVariable(
- isComparison(Opcode) ? IceType_i32 : Left.toOperand()->getType());
+ BooleanVariable *BoolDest = nullptr;
+ Variable *Dest = nullptr;
+ if (isComparison(Opcode)) {
+ BoolDest = makeVariable<BooleanVariable>(IceType_i32);
+ Dest = BoolDest;
+ } else {
+ Dest = makeVariable(Left.toOperand()->getType());
+ }
switch (Opcode) {
case kExprI32Add:
case kExprI64Add:
@@ -538,6 +544,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Ne, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -547,6 +554,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Eq, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -556,6 +564,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Slt, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -565,6 +574,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Sle, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -574,6 +584,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Uge, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -583,6 +594,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Ule, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -592,6 +604,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Ult, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -601,6 +614,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Sge, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -610,6 +624,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Sgt, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -619,6 +634,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Ugt, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -628,6 +644,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Ueq, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -637,6 +654,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Une, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -646,6 +664,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Ule, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -655,6 +674,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Ult, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -664,6 +684,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Uge, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -673,6 +694,7 @@
auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Ugt, TmpDest, Left, Right));
+ BoolDest->setBoolSource(TmpDest);
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break;
@@ -688,22 +710,26 @@
Node Unop(wasm::WasmOpcode Opcode, Node Input) {
LOG(out << "Unop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Input
<< ") = ");
- Ice::Variable *Dest = nullptr;
+ Variable *Dest = nullptr;
switch (Opcode) {
// TODO (eholk): merge these next two cases using getConstantInteger
case kExprI32Eqz: {
- Dest = makeVariable(IceType_i32);
+ auto *BoolDest = makeVariable<BooleanVariable>(IceType_i32);
+ Dest = BoolDest;
auto *Tmp = makeVariable(IceType_i1);
Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input,
Ctx->getConstantInt32(0)));
+ BoolDest->setBoolSource(Tmp);
Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp));
break;
}
case kExprI64Eqz: {
- Dest = makeVariable(IceType_i32);
+ auto *BoolDest = makeVariable<BooleanVariable>(IceType_i32);
+ Dest = BoolDest;
auto *Tmp = makeVariable(IceType_i1);
Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input,
Ctx->getConstantInt64(0)));
+ BoolDest->setBoolSource(Tmp);
Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp));
break;
}
@@ -948,9 +974,12 @@
LOG(out << *TrueNode << ", " << *FalseNode << ")"
<< "\n");
- auto *CondBool = makeVariable(IceType_i1);
- Ctrl->appendInst(InstIcmp::create(Func, InstIcmp::Ne, CondBool, Cond,
- Ctx->getConstantInt32(0)));
+ auto *CondBool = Cond.toOperand()->asBoolean();
+ if (CondBool == nullptr) {
+ CondBool = makeVariable(IceType_i1);
+ Ctrl->appendInst(InstIcmp::create(Func, InstIcmp::Ne, CondBool, Cond,
+ Ctx->getConstantInt32(0)));
+ }
Ctrl->appendInst(InstBr::create(Func, CondBool, *TrueNode, *FalseNode));
return OperandNode(nullptr);
@@ -1183,7 +1212,7 @@
Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr));
// and cast, if needed
- Ice::Variable *Result = nullptr;
+ Variable *Result = nullptr;
if (toIceType(Type) != toIceType(MemType)) {
auto DestType = toIceType(Type);
Result = makeVariable(DestType);
@@ -1278,12 +1307,13 @@
PhiMap.emplace(Op, Phi);
}
- Ice::Variable *makeVariable(Ice::Type Type) {
- return makeVariable(Type, Control());
+ template <typename T = Variable> T *makeVariable(Ice::Type Type) {
+ return makeVariable<T>(Type, Control());
}
- Ice::Variable *makeVariable(Ice::Type Type, CfgNode *DefNode) {
- auto *Var = Func->makeVariable(Type);
+ template <typename T = Variable>
+ T *makeVariable(Ice::Type Type, CfgNode *DefNode) {
+ auto *Var = Func->makeVariable<T>(Type);
DefNodeMap.emplace(Var, DefNode);
return Var;
}
@@ -1360,12 +1390,9 @@
Base = Addr;
}
- // Do the bounds check.
- //
- // TODO (eholk): Add a command line argument to control whether bounds
- // checks are inserted, and maybe add a way to duplicate bounds checks to
- // get a better sense of the overhead.
- if (!llvm::dyn_cast<ConstantInteger32>(Base)) {
+ // Do the bounds check if enabled
+ if (getFlags().getWasmBoundsCheck() &&
+ !llvm::isa<ConstantInteger32>(Base)) {
// TODO (eholk): creating a new basic block on every memory access is
// terrible (see https://goo.gl/Zj7DTr). Try adding a new instruction that
// encapsulates this "abort if false" pattern.