aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-02-06 17:16:32 -0500
committerAlon Zakai <alonzakai@gmail.com>2014-02-06 17:16:32 -0500
commit80064ba8c5da328b8ace635011e2ab4a00d40676 (patch)
tree8c83b1018e85ceb2136c255bb7ce1514e2bfcc9a
parent1296ba6b4d429762ff2c4a93b27d8a148590fdc7 (diff)
optimize partially aligned memcpys
-rw-r--r--lib/Target/JSBackend/CallHandlers.h43
1 files changed, 24 insertions, 19 deletions
diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h
index 11a8cdad0e..979bf8a46b 100644
--- a/lib/Target/JSBackend/CallHandlers.h
+++ b/lib/Target/JSBackend/CallHandlers.h
@@ -237,30 +237,35 @@ DEF_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32, {
if (AlignInt) {
ConstantInt *LenInt = dyn_cast<ConstantInt>(CI->getOperand(2));
if (LenInt) {
+ // we can emit inline code for this
unsigned Len = LenInt->getZExtValue();
- if (Len == 0) return ""; // after here, we can assume Len>1
- 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
+ if (Len <= WRITE_LOOP_MAX) {
+ unsigned Align = AlignInt->getZExtValue();
+ if (Align > 4) Align = 4;
+ unsigned Pos = 0;
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";
+ while (Len > 0) {
+ // handle as much as we can in the current alignment
+ unsigned CurrLen = Align*(Len/Align);
+ unsigned Factor = CurrLen/Align;
+ if (Factor <= UNROLL_LOOP_MAX) {
+ // unroll
+ for (unsigned Offset = 0; Offset < CurrLen; Offset += Align) {
+ std::string Add = "+" + utostr(Pos + Offset) + (Align == 1 ? "|0" : "");
+ Ret += ";" + getHeapAccess(Dest + Add, Align) + "=" + getHeapAccess(Src + Add, Align) + "|0";
+ }
+ } else {
+ // emit a loop
+ UsedVars["dest"] = UsedVars["src"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext())->getTypeID();
+ Ret += "dest=" + Dest + "+" + utostr(Pos) + "|0; src=" + Src + "+" + utostr(Pos) + "|0; stop=dest+" + utostr(CurrLen) + "|0; do { " + getHeapAccess("dest", Align) + "=" + getHeapAccess("src", Align) + "|0; dest=dest+" + utostr(Align) + "|0; src=src+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0));";
}
- return Ret;
- } else if (Len <= WRITE_LOOP_MAX) {
- // emit a loop
- UsedVars["dest"] = UsedVars["src"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext())->getTypeID();
- return "dest=" + Dest + "; src=" + Src + "; stop=" + Dest + "+" + utostr(Len) + "|0; do { " + getHeapAccess("dest", Align) + "=" + getHeapAccess("src", Align) + "|0; dest=dest+" + utostr(Align) + "|0; src=src+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0));";
+ Pos += CurrLen;
+ Len -= CurrLen;
+ Align /= 2;
}
+ return Ret;
}
}
}
@@ -286,10 +291,10 @@ DEF_CALL_HANDLER(llvm_memset_p0i8_i32, {
if (Align > 4) Align = 4;
unsigned Pos = 0;
std::string Ret;
+ std::string Dest = getValueAsStr(CI->getOperand(0));
while (Len > 0) {
// handle as much as we can in the current alignment
unsigned CurrLen = Align*(Len/Align);
- std::string Dest = getValueAsStr(CI->getOperand(0));
unsigned FullVal = 0;
for (unsigned i = 0; i < Align; i++) {
FullVal <<= 8;