static void _CustomWriteIntUnrolledSigned_ThunkWriter(ref ThunkWriter writer, int num, char[] buffer) { // Why signed integers? // Earlier versions of this code used unsigned integers, // but it turns out that's not ideal and here's why. // // The signed version of the relevant code gets JIT'd down to: // instr operands latency/throughput (approx. worst case; Haswell) // ======================================================================================== // mov ecx,### 2 / 0.5 // cdq 1 / - // idiv eax,ecx 29 / 11 // mov ecx,### 2 / 0.5 // cdq 1 / - // idiv eax,ecx 29 / 11 // movsx edx,dl - / 0.5 // // The unsigned version gets JIT'd down to: // instr operands latency/throughput (approx. worst case; Haswell) // ======================================================================================== // mov ecx,### 2 / 0.5 // xor edx,edx 1 / 0.25 // div eax,ecx 29 / 11 // mov ecx,### 2 / 0.5 // xor edx,edx 1 / 0.25 // div eax,ecx 29 / 11 // and edx,### 1 / 0.25 // // In theory div (usigned division) is faster than idiv, and it probably is *but* cdq + cdq + movsx is // faster than xor + xor + and; in practice it's fast *enough* to make up the difference. // have to special case this, we can't negate it if (num == int.MinValue) { writer.WriteMinConstant(ConstantString_Min.Int_MinValue); return; } int numLen; int number; if (num < 0) { writer.Write('-'); number = -num; } else { number = num; } if (number < 1000) { if (number >= 100) { writer.Write(DigitTriplets, number * 3, 3); } else { if (number >= 10) { writer.Write(DigitTriplets, number * 3 + 1, 2); } else { writer.Write(DigitTriplets, number * 3 + 2, 1); } } return; } var d012 = number % 1000 * 3; int d543; if (number < 1000000) { d543 = (number / 1000) * 3; if (number >= 100000) { numLen = 6; goto digit5; } else { if (number >= 10000) { numLen = 5; goto digit4; } else { numLen = 4; goto digit3; } } } d543 = (number / 1000) % 1000 * 3; int d876; if (number < 1000000000) { d876 = (number / 1000000) * 3; if (number >= 100000000) { numLen = 9; goto digit8; } else { if (number >= 10000000) { numLen = 8; goto digit7; } else { numLen = 7; goto digit6; } } } d876 = (number / 1000000) % 1000 * 3; numLen = 10; // uint is between 0 & 4,294,967,295 (in practice we only get to int.MaxValue, but that's the same # of digits) // so 1 to 10 digits // [01,]000,000-[99,]000,000 var d9 = number / 1000000000; buffer[0] = (char)('0' + d9); digit8: buffer[1] = DigitTriplets[d876]; digit7: buffer[2] = DigitTriplets[d876 + 1]; digit6: buffer[3] = DigitTriplets[d876 + 2]; digit5: buffer[4] = DigitTriplets[d543]; digit4: buffer[5] = DigitTriplets[d543 + 1]; digit3: buffer[6] = DigitTriplets[d543 + 2]; buffer[7] = DigitTriplets[d012]; buffer[8] = DigitTriplets[d012 + 1]; buffer[9] = DigitTriplets[d012 + 2]; writer.Write(buffer, 10 - numLen, numLen); }
static void _CustomWriteInt_ThunkWriter(ref ThunkWriter writer, int number, char[] buffer) { // Gotta special case this, we can't negate it if (number == int.MinValue) { writer.WriteMinConstant(ConstantString_Min.Int_MinValue); return; } var ptr = InlineSerializer<object>.CharBufferSize - 1; uint copy; if (number < 0) { writer.Write('-'); copy = (uint)(-number); } else { copy = (uint)number; } do { byte ix = (byte)(copy % 100); copy /= 100; var chars = DigitPairs[ix]; buffer[ptr--] = chars.Second; buffer[ptr--] = chars.First; } while (copy != 0); if (buffer[ptr + 1] == '0') { ptr++; } writer.Write(buffer, ptr + 1, InlineSerializer<object>.CharBufferSize - 1 - ptr); }