# PATCH: zend_alloc.c x86_64 optimization

- Thread: https://externals.io/message/33488
- Original archive: https://news-web.php.net/php.internals/33488
- Started by Brian Shire on 2007-11-28T22:27:29+00:00
- Messages: 1
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #33488 — Brian Shire — 2007-11-28T22:27:29+00:00

URL: https://externals.io/message/33488#33488

I noticed that there where some x86_64 assembly optimizations missing  
from Zend/zend_alloc.c, it only accounts for i386.  The following  
patch should add x86_64 support (I don't have karma for Zend of  
course, patch is against 5.2.5), I've included a bench mark with a  
simple test script to test out memory allocation.  I'd be interested  
in getting feedback on this and knowing what other's results are.   
Sorry for the custom micro-bench but zend_bench.php did show small  
gains, but they where extremely small to really show anything.

A note on the i386 assembly, I had to add the following '&' char to  
make sure the input/outputs are using different registers.  Lack of  
this had caused some serious memory corruption on my system with -O2  
so I'm guessing it might be appropriate to do the same on the i386  
code as well, but I've left that out of this patch, perhaps someone  
with some assembler experience can verify this is correct?

-					: "=a"(res), "=d" (overflow)
+					: "=&a"(res), "=&d" (overflow)


Thanks,

-shire



<?php
$start = microtime(true);
for($i=0; $i< 1000000; $i++) {
   $x[$i] = 'xxxxx';
}
$stop = microtime(true);
print ($stop-$start)."\n";
?>




php-5.2.5
-----------
	no-asm		asm		delta
-----------------------------------------------------
Run1	0.926729918	0.767436981	-0.159292936
Run2	0.920269966	0.768045902	-0.152224064
Run3	0.918609858	0.758006096	-0.160603762
Total	2.765609741	2.293488979	-0.472120762
Percentage:				-17.07%




Index: Zend/zend_alloc.c
===================================================================
--- Zend/zend_alloc.c	(revision 69567)
+++ Zend/zend_alloc.c	(working copy)
@@ -656,6 +656,11 @@

  	__asm__("bsrl %1,%0\n\t" : "=r" (n) : "rm"  (_size));
  	return n;
+#elif defined(__GNUC__) && defined(__x86_64__)
+	unsigned long n;
+
+	__asm__("bsrq %1,%0\n\t" : "=r" (n) : "rm" (_size));
+	return (unsigned int)n;
  #elif defined(_MSC_VER) && defined(_M_IX86)
  	__asm {
  		bsr eax, _size
@@ -677,6 +682,11 @@

  	__asm__("bsfl %1,%0\n\t" : "=r" (n) : "rm"  (_size));
  	return n;
+#elif defined(__GNUC__) && defined(__x86_64__)
+	unsigned long n;
+
+	__asm__("bsfq %1,%0\n\t" : "=r" (n) : "rm" (_size));
+  return (unsigned int)n;
  #elif defined(_MSC_VER) && defined(_M_IX86)
  	__asm {
  		bsf eax, _size
@@ -2309,18 +2319,30 @@
  	return _zend_mm_block_size(AG(mm_heap), ptr  
ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  }

-#if defined(__GNUC__) && defined(i386)
+#if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))

  static inline size_t safe_address(size_t nmemb, size_t size, size_t  
offset)
  {
  	size_t res = nmemb;
-	unsigned long overflow ;
+	unsigned long overflow = 0;

-	__asm__ ("mull %3\n\taddl %4,%0\n\tadcl $0,%1"
+#if defined(i386)
+	__asm__ (	"mull %3    \n\t"
+						"addl %4,%0 \n\t"
+						"adcl $0,%1 \n\t"
  	     : "=a"(res), "=d" (overflow)
  	     : "%0"(res),
  	       "rm"(size),
  	       "rm"(offset));
+#else /* __x86_64__ */
+	__asm__ (	"mulq %3     \n\t"
+						"addq %4,%0  \n\t"
+						"adcq $0,%1  \n\t"
+					: "=&a"(res), "=&d" (overflow)
+					: "%0"(res),
+						"rm"(size),
+						"rm"(offset) );
+#endif
  	
  	if (UNEXPECTED(overflow)) {
  		zend_error_noreturn(E_ERROR, "Possible integer overflow in memory  
allocation (%zu * %zu + %zu)", nmemb, size, offset);
