Commit 80ee5b3f by Eric Holk

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 .
parent 7146e997
...@@ -345,7 +345,11 @@ struct dev_list_flag {}; ...@@ -345,7 +345,11 @@ struct dev_list_flag {};
\ \
X(VerboseFocusOnString, std::string, dev_opt_flag, "verbose-focus", \ X(VerboseFocusOnString, std::string, dev_opt_flag, "verbose-focus", \
cl::desc("Override with -verbose=none except for specified functions"), \ cl::desc("Override with -verbose=none except for specified functions"), \
cl::init(":")) cl::init(":")) \
\
X(WasmBoundsCheck, bool, dev_opt_flag, "wasm-bounds-check", \
cl::desc("Add bounds checking code in WASM frontend"), \
cl::init(true))
//#define X(Name, Type, ClType, ...) //#define X(Name, Type, ClType, ...)
} // end of namespace Ice } // end of namespace Ice
......
...@@ -51,6 +51,7 @@ public: ...@@ -51,6 +51,7 @@ public:
kConst_Max = kConst_Target + MaxTargetKinds, kConst_Max = kConst_Target + MaxTargetKinds,
kVariable, kVariable,
kVariable64On32, kVariable64On32,
kVariableBoolean,
kVariable_Target, // leave space for target-specific variable kinds kVariable_Target, // leave space for target-specific variable kinds
kVariable_Max = kVariable_Target + MaxTargetKinds, kVariable_Max = kVariable_Target + MaxTargetKinds,
// Target-specific operand classes use kTarget as the starting point for // Target-specific operand classes use kTarget as the starting point for
...@@ -95,6 +96,8 @@ public: ...@@ -95,6 +96,8 @@ public:
virtual ~Operand() = default; virtual ~Operand() = default;
virtual Variable *asBoolean() { return nullptr; }
protected: protected:
Operand(OperandKind Kind, Type Ty) : Ty(Ty), Kind(Kind) { Operand(OperandKind Kind, Type Ty) : Ty(Ty), Kind(Kind) {
// It is undefined behavior to have a larger value in the enum // It is undefined behavior to have a larger value in the enum
...@@ -984,6 +987,35 @@ private: ...@@ -984,6 +987,35 @@ private:
const static InstDefList NoDefinitions; const static InstDefList NoDefinitions;
}; };
/// BooleanVariable represents a variable that was the zero-extended result of a
/// comparison. It maintains a pointer to its original i1 source so that the
/// WASM frontend can avoid adding needless comparisons.
class BooleanVariable : public Variable {
BooleanVariable() = delete;
BooleanVariable(const BooleanVariable &) = delete;
BooleanVariable &operator=(const BooleanVariable &) = delete;
BooleanVariable(const Cfg *Func, OperandKind K, Type Ty, SizeT Index)
: Variable(Func, K, Ty, Index) {}
public:
static BooleanVariable *create(Cfg *Func, Type Ty, SizeT Index) {
return new (Func->allocate<BooleanVariable>())
BooleanVariable(Func, kVariable, Ty, Index);
}
virtual Variable *asBoolean() { return BoolSource; }
void setBoolSource(Variable *Src) { BoolSource = Src; }
static bool classof(const Operand *Operand) {
return Operand->getKind() == kVariableBoolean;
}
private:
Variable *BoolSource = nullptr;
};
} // end of namespace Ice } // end of namespace Ice
#endif // SUBZERO_SRC_ICEOPERAND_H #endif // SUBZERO_SRC_ICEOPERAND_H
...@@ -49,7 +49,6 @@ ...@@ -49,7 +49,6 @@
using namespace std; using namespace std;
using namespace Ice; using namespace Ice;
using namespace v8;
using namespace v8::internal; using namespace v8::internal;
using namespace v8::internal::wasm; using namespace v8::internal::wasm;
using v8::internal::wasm::DecodeWasmModule; using v8::internal::wasm::DecodeWasmModule;
...@@ -255,6 +254,7 @@ bool isComparison(wasm::WasmOpcode Opcode) { ...@@ -255,6 +254,7 @@ bool isComparison(wasm::WasmOpcode Opcode) {
class IceBuilder { class IceBuilder {
using Node = OperandNode; using Node = OperandNode;
using Variable = Ice::Variable;
IceBuilder() = delete; IceBuilder() = delete;
IceBuilder(const IceBuilder &) = delete; IceBuilder(const IceBuilder &) = delete;
...@@ -393,8 +393,14 @@ public: ...@@ -393,8 +393,14 @@ public:
Node Binop(wasm::WasmOpcode Opcode, Node Left, Node Right) { Node Binop(wasm::WasmOpcode Opcode, Node Left, Node Right) {
LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left
<< ", " << Right << ") = "); << ", " << Right << ") = ");
auto *Dest = makeVariable( BooleanVariable *BoolDest = nullptr;
isComparison(Opcode) ? IceType_i32 : Left.toOperand()->getType()); Variable *Dest = nullptr;
if (isComparison(Opcode)) {
BoolDest = makeVariable<BooleanVariable>(IceType_i32);
Dest = BoolDest;
} else {
Dest = makeVariable(Left.toOperand()->getType());
}
switch (Opcode) { switch (Opcode) {
case kExprI32Add: case kExprI32Add:
case kExprI64Add: case kExprI64Add:
...@@ -538,6 +544,7 @@ public: ...@@ -538,6 +544,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Ne, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Ne, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -547,6 +554,7 @@ public: ...@@ -547,6 +554,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Eq, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Eq, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -556,6 +564,7 @@ public: ...@@ -556,6 +564,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Slt, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Slt, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -565,6 +574,7 @@ public: ...@@ -565,6 +574,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Sle, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Sle, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -574,6 +584,7 @@ public: ...@@ -574,6 +584,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Uge, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Uge, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -583,6 +594,7 @@ public: ...@@ -583,6 +594,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Ule, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Ule, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -592,6 +604,7 @@ public: ...@@ -592,6 +604,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Ult, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Ult, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -601,6 +614,7 @@ public: ...@@ -601,6 +614,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Sge, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Sge, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -610,6 +624,7 @@ public: ...@@ -610,6 +624,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Sgt, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Sgt, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -619,6 +634,7 @@ public: ...@@ -619,6 +634,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstIcmp::create(Func, InstIcmp::Ugt, TmpDest, Left, Right)); InstIcmp::create(Func, InstIcmp::Ugt, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -628,6 +644,7 @@ public: ...@@ -628,6 +644,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Ueq, TmpDest, Left, Right)); InstFcmp::create(Func, InstFcmp::Ueq, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -637,6 +654,7 @@ public: ...@@ -637,6 +654,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Une, TmpDest, Left, Right)); InstFcmp::create(Func, InstFcmp::Une, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -646,6 +664,7 @@ public: ...@@ -646,6 +664,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Ule, TmpDest, Left, Right)); InstFcmp::create(Func, InstFcmp::Ule, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -655,6 +674,7 @@ public: ...@@ -655,6 +674,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Ult, TmpDest, Left, Right)); InstFcmp::create(Func, InstFcmp::Ult, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -664,6 +684,7 @@ public: ...@@ -664,6 +684,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Uge, TmpDest, Left, Right)); InstFcmp::create(Func, InstFcmp::Uge, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -673,6 +694,7 @@ public: ...@@ -673,6 +694,7 @@ public:
auto *TmpDest = makeVariable(IceType_i1); auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst( Control()->appendInst(
InstFcmp::create(Func, InstFcmp::Ugt, TmpDest, Left, Right)); InstFcmp::create(Func, InstFcmp::Ugt, TmpDest, Left, Right));
BoolDest->setBoolSource(TmpDest);
Control()->appendInst( Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, TmpDest)); InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
break; break;
...@@ -688,22 +710,26 @@ public: ...@@ -688,22 +710,26 @@ public:
Node Unop(wasm::WasmOpcode Opcode, Node Input) { Node Unop(wasm::WasmOpcode Opcode, Node Input) {
LOG(out << "Unop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Input LOG(out << "Unop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Input
<< ") = "); << ") = ");
Ice::Variable *Dest = nullptr; Variable *Dest = nullptr;
switch (Opcode) { switch (Opcode) {
// TODO (eholk): merge these next two cases using getConstantInteger // TODO (eholk): merge these next two cases using getConstantInteger
case kExprI32Eqz: { case kExprI32Eqz: {
Dest = makeVariable(IceType_i32); auto *BoolDest = makeVariable<BooleanVariable>(IceType_i32);
Dest = BoolDest;
auto *Tmp = makeVariable(IceType_i1); auto *Tmp = makeVariable(IceType_i1);
Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input, Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input,
Ctx->getConstantInt32(0))); Ctx->getConstantInt32(0)));
BoolDest->setBoolSource(Tmp);
Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp)); Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp));
break; break;
} }
case kExprI64Eqz: { case kExprI64Eqz: {
Dest = makeVariable(IceType_i32); auto *BoolDest = makeVariable<BooleanVariable>(IceType_i32);
Dest = BoolDest;
auto *Tmp = makeVariable(IceType_i1); auto *Tmp = makeVariable(IceType_i1);
Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input, Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input,
Ctx->getConstantInt64(0))); Ctx->getConstantInt64(0)));
BoolDest->setBoolSource(Tmp);
Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp)); Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp));
break; break;
} }
...@@ -948,9 +974,12 @@ public: ...@@ -948,9 +974,12 @@ public:
LOG(out << *TrueNode << ", " << *FalseNode << ")" LOG(out << *TrueNode << ", " << *FalseNode << ")"
<< "\n"); << "\n");
auto *CondBool = makeVariable(IceType_i1); auto *CondBool = Cond.toOperand()->asBoolean();
if (CondBool == nullptr) {
CondBool = makeVariable(IceType_i1);
Ctrl->appendInst(InstIcmp::create(Func, InstIcmp::Ne, CondBool, Cond, Ctrl->appendInst(InstIcmp::create(Func, InstIcmp::Ne, CondBool, Cond,
Ctx->getConstantInt32(0))); Ctx->getConstantInt32(0)));
}
Ctrl->appendInst(InstBr::create(Func, CondBool, *TrueNode, *FalseNode)); Ctrl->appendInst(InstBr::create(Func, CondBool, *TrueNode, *FalseNode));
return OperandNode(nullptr); return OperandNode(nullptr);
...@@ -1183,7 +1212,7 @@ public: ...@@ -1183,7 +1212,7 @@ public:
Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr)); Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr));
// and cast, if needed // and cast, if needed
Ice::Variable *Result = nullptr; Variable *Result = nullptr;
if (toIceType(Type) != toIceType(MemType)) { if (toIceType(Type) != toIceType(MemType)) {
auto DestType = toIceType(Type); auto DestType = toIceType(Type);
Result = makeVariable(DestType); Result = makeVariable(DestType);
...@@ -1278,12 +1307,13 @@ private: ...@@ -1278,12 +1307,13 @@ private:
PhiMap.emplace(Op, Phi); PhiMap.emplace(Op, Phi);
} }
Ice::Variable *makeVariable(Ice::Type Type) { template <typename T = Variable> T *makeVariable(Ice::Type Type) {
return makeVariable(Type, Control()); return makeVariable<T>(Type, Control());
} }
Ice::Variable *makeVariable(Ice::Type Type, CfgNode *DefNode) { template <typename T = Variable>
auto *Var = Func->makeVariable(Type); T *makeVariable(Ice::Type Type, CfgNode *DefNode) {
auto *Var = Func->makeVariable<T>(Type);
DefNodeMap.emplace(Var, DefNode); DefNodeMap.emplace(Var, DefNode);
return Var; return Var;
} }
...@@ -1360,12 +1390,9 @@ private: ...@@ -1360,12 +1390,9 @@ private:
Base = Addr; Base = Addr;
} }
// Do the bounds check. // Do the bounds check if enabled
// if (getFlags().getWasmBoundsCheck() &&
// TODO (eholk): Add a command line argument to control whether bounds !llvm::isa<ConstantInteger32>(Base)) {
// 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)) {
// TODO (eholk): creating a new basic block on every memory access is // TODO (eholk): creating a new basic block on every memory access is
// terrible (see https://goo.gl/Zj7DTr). Try adding a new instruction that // terrible (see https://goo.gl/Zj7DTr). Try adding a new instruction that
// encapsulates this "abort if false" pattern. // encapsulates this "abort if false" pattern.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment