diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-02-06 11:44:49 -0500 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-02-06 12:13:18 -0500 |
commit | cc26dd73794182e7f4ac0d1143789630ba305426 (patch) | |
tree | 80b76f52f685d61079c51ff1ed5b0b1ddcbc6365 | |
parent | 4a3d10c6d7faac653b6bff61ab6fcd863dfb3864 (diff) |
optimize small constant memcpy
-rw-r--r-- | lib/Target/JSBackend/CallHandlers.h | 35 | ||||
-rw-r--r-- | lib/Target/JSBackend/JSBackend.cpp | 32 |
2 files changed, 53 insertions, 14 deletions
diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index b3d4799fa0..0568d98db0 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -226,7 +226,42 @@ DEF_CALL_HANDLER(llvm_nacl_atomic_store_i32, { return "HEAP32[" + getValueAsStr(CI->getOperand(0)) + ">>2]=" + getValueAsStr(CI->getOperand(1)); }) +#define UNROLL_LOOP_MAX 8 +#define WRITE_LOOP_MAX 128 + DEF_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32, { + if (CI) { + ConstantInt *AlignInt = dyn_cast<ConstantInt>(CI->getOperand(3)); + if (AlignInt) { + ConstantInt *LenInt = dyn_cast<ConstantInt>(CI->getOperand(2)); + if (LenInt) { + unsigned Len = LenInt->getZExtValue(); + unsigned Align = AlignInt->getZExtValue(); + while (Align > 0 && Len % Align != 0) Align /= 2; // a very unaligned small number of bytes can still be unrolled in some cases + if (Align > 4) Align = 4; + if (Align > 0 && Len % Align == 0) { + // we can emit inline code for this + std::string Ret; + std::string Dest = getValueAsStr(CI->getOperand(0)); + std::string Src = getValueAsStr(CI->getOperand(1)); + unsigned Factor = Len/Align; + if (Factor <= UNROLL_LOOP_MAX) { + // unroll + if (Len > 0) Ret += getHeapAccess(Dest, Align) + "=" + getHeapAccess(Src, Align) + "|0"; + for (unsigned Offset = Align; Offset < Len; Offset += Align) { + std::string Add = "+" + utostr(Offset) + (Align == 1 ? "|0" : ""); + Ret += ";" + getHeapAccess(Dest + Add, Align) + "=" + getHeapAccess(Src + Add, Align) + "|0"; + } + return Ret; + } else if (Len <= WRITE_LOOP_MAX) { + // emit a loop + UsedVars["dest"] = UsedVars["src"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext())->getTypeID(); + return "for (dest=" + Dest + ", src=" + Src + ", stop=(" + Dest + "+" + utostr(Len) + ")|0; (dest|0) < (stop|0); dest=(dest+" + utostr(Align) + ")|0, src=(src+" + utostr(Align) + ")|0) { " + getHeapAccess("dest", Align) + "=" + getHeapAccess("src", Align) + "|0; }"; + } + } + } + } + } Declares.insert("memcpy"); Redirects["llvm_memcpy_p0i8_p0i8_i32"] = "memcpy"; return CH___default__(CI, "_memcpy", 3) + "|0"; diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 82769e6370..1bee376b32 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -321,6 +321,7 @@ namespace { } std::string getPtrLoad(const Value* Ptr); + std::string getHeapAccess(const std::string& Name, unsigned Bytes, bool Integer=true); std::string getPtrUse(const Value* Ptr); std::string getConstant(const Constant*, AsmCast sign=ASM_SIGNED); std::string getValueAsStr(const Value*, AsmCast sign=ASM_SIGNED); @@ -747,6 +748,22 @@ std::string JSWriter::getPtrLoad(const Value* Ptr) { return getCast(getPtrUse(Ptr), t, ASM_NONSPECIFIC); } +std::string JSWriter::getHeapAccess(const std::string& Name, unsigned Bytes, bool Integer) { + switch (Bytes) { + default: assert(false && "Unsupported type"); + case 8: return "HEAPF64[" + Name + ">>3]"; + case 4: { + if (Integer) { + return "HEAP32[" + Name + ">>2]"; + } else { + return "HEAPF32[" + Name + ">>2]"; + } + } + case 2: return "HEAP16[" + Name + ">>1]"; + case 1: return "HEAP8[" + Name + "]"; + } +} + std::string JSWriter::getPtrUse(const Value* Ptr) { Type *t = cast<PointerType>(Ptr->getType())->getElementType(); unsigned Bytes = t->getPrimitiveSizeInBits()/8; @@ -767,20 +784,7 @@ std::string JSWriter::getPtrUse(const Value* Ptr) { case 1: return "HEAP8[" + utostr(Addr) + "]"; } } else { - std::string Name = getOpName(Ptr); - switch (Bytes) { - default: assert(false && "Unsupported type"); - case 8: return "HEAPF64[" + Name + ">>3]"; - case 4: { - if (t->isIntegerTy()) { - return "HEAP32[" + Name + ">>2]"; - } else { - return "HEAPF32[" + Name + ">>2]"; - } - } - case 2: return "HEAP16[" + Name + ">>1]"; - case 1: return "HEAP8[" + Name + "]"; - } + return getHeapAccess(getOpName(Ptr), Bytes, t->isIntegerTy()); } } |