aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-02-06 11:44:49 -0500
committerAlon Zakai <alonzakai@gmail.com>2014-02-06 12:13:18 -0500
commitcc26dd73794182e7f4ac0d1143789630ba305426 (patch)
tree80b76f52f685d61079c51ff1ed5b0b1ddcbc6365
parent4a3d10c6d7faac653b6bff61ab6fcd863dfb3864 (diff)
optimize small constant memcpy
-rw-r--r--lib/Target/JSBackend/CallHandlers.h35
-rw-r--r--lib/Target/JSBackend/JSBackend.cpp32
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());
}
}