Skip to content

Commit

Permalink
Added ability to avoid code generation for useless opcode handlers.
Browse files Browse the repository at this point in the history
- SPEC(NO_CONST_CONST) may prevent codegeneration for handlers like ADD_SPEC_CONST_CONST. Compiler and optimizaer should care about constants folding.
- SPEC(COMMUTATIVE) generate only single handler instead of two eqivalents like ADD_SPEC_CONST_CV and ADD_SPEC_CV_CONST. Compiler and optimizer should care avout operands swapping.
  • Loading branch information
dstogov committed Mar 11, 2016
1 parent c1b8c4d commit 7f80514
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 18 deletions.
91 changes: 74 additions & 17 deletions Zend/zend_vm_gen.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"ZEND_VM_EXT_ARG_NUM" => 1<<18,
"ZEND_VM_EXT_ARRAY_INIT" => 1<<19,
"ZEND_VM_EXT_REF" => 1<<20,
"ZEND_VM_EXT_MASK" => 0xff000000,
"ZEND_VM_EXT_MASK" => 0x0f000000,
"ZEND_VM_EXT_NUM" => 0x01000000,
// unused 0x2000000
"ZEND_VM_EXT_JMP_ADDR" => 0x03000000,
Expand All @@ -87,6 +87,8 @@
"ZEND_VM_EXT_FAST_RET" => 0x0a000000,
"ZEND_VM_EXT_SRC" => 0x0b000000,
"ZEND_VM_EXT_SEND" => 0x0c000000,
"ZEND_VM_NO_CONST_CONST" => 0x40000000,
"ZEND_VM_COMMUTATIVE" => 0x80000000,
);

foreach ($vm_op_flags as $name => $val) {
Expand Down Expand Up @@ -179,6 +181,17 @@
"TMPVARCV" => 0,
);

$commutative_order = array(
"ANY" => 0,
"TMP" => 1,
"VAR" => 2,
"CONST" => 0,
"UNUSED" => 0,
"CV" => 4,
"TMPVAR" => 2,
"TMPVARCV" => 4,
);

$op1_type = array(
"ANY" => "opline->op1_type",
"TMP" => "IS_TMP_VAR",
Expand Down Expand Up @@ -908,7 +921,21 @@ function($matches) use ($spec, $prefix, $op1, $op2) {

// Generates opcode handler
function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, $extra_spec = null, &$switch_labels = array()) {
global $definition_file, $prefix, $typecode, $opnames;
global $definition_file, $prefix, $typecode, $opnames, $commutative_order;

if ($spec &&
isset($extra_spec["NO_CONST_CONST"]) &&
$op1 == "CONST" && $op2 == "CONST") {
// Skip useless constant handlers
return;
}

if ($spec &&
isset($extra_spec["COMMUTATIVE"]) &&
$commutative_order[$op1] > $commutative_order[$op2]) {
// Skip duplicate commutative handlers
return;
}

if (ZEND_VM_LINES) {
out($f, "#line $lineno \"$definition_file\"\n");
Expand Down Expand Up @@ -982,6 +1009,21 @@ function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno,
gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name);
}


function gen_null_label($f, $kind, $prolog) {
switch ($kind) {
case ZEND_VM_KIND_CALL:
out($f,$prolog."ZEND_NULL_HANDLER,\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f,$prolog."(void*)(uintptr_t)-1,\n");
break;
case ZEND_VM_KIND_GOTO:
out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n");
break;
}
}

// Generates array of opcode handlers (specialized or unspecialized)
function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()) {
global $opcodes, $op_types, $prefix;
Expand Down Expand Up @@ -1099,13 +1141,28 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
};
};
$generate = function ($op1, $op2, $extra_spec = array()) use ($f, $kind, $dsc, $prefix, $prolog, $num, $switch_labels, &$label) {
global $typecode;
global $typecode, $commutative_order;

// Check if specialized handler is defined
/* TODO: figure out better way to signal "specialized and not defined" than an extra lookup */
if (isset($dsc["op1"][$op1]) &&
isset($dsc["op2"][$op2]) &&
(!isset($extra_spec["OP_DATA"]) || isset($dsc["spec"]["OP_DATA"][$extra_spec["OP_DATA"]]))) {

if (isset($extra_spec["NO_CONST_CONST"]) &&
$op1 == "CONST" && $op2 == "CONST") {
// Skip useless constant handlers
gen_null_label($f, $kind, $prolog);
$label++;
return;
} else if (isset($extra_spec["COMMUTATIVE"]) &&
$commutative_order[$op1] > $commutative_order[$op2]) {
// Skip duplicate commutative handlers
gen_null_label($f, $kind, $prolog);
$label++;
return;
}

// Emit pointer to specialized handler
$spec_name = $dsc["op"]."_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec);
switch ($kind) {
Expand All @@ -1124,20 +1181,8 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
}
} else {
// Emit pointer to handler of undefined opcode
switch ($kind) {
case ZEND_VM_KIND_CALL:
out($f,$prolog."ZEND_NULL_HANDLER,\n");
$label++;
break;
case ZEND_VM_KIND_SWITCH:
out($f,$prolog."(void*)(uintptr_t)-1,\n");
$label++;
break;
case ZEND_VM_KIND_GOTO:
out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n");
$label++;
break;
}
gen_null_label($f, $kind, $prolog);
$label++;
}
};

Expand Down Expand Up @@ -1805,6 +1850,12 @@ function parse_spec_rules($def, $lineno, $str) {
case "SMART_BRANCH":
$ret["SMART_BRANCH"] = array(0, 1, 2);
break;
case "NO_CONST_CONST":
$ret["NO_CONST_CONST"] = array(1);
break;
case "COMMUTATIVE":
$ret["COMMUTATIVE"] = array(1);
break;
default:
die("ERROR ($def:$lineno): Wrong specialization rules '$str'\n");
}
Expand Down Expand Up @@ -1877,6 +1928,12 @@ function gen_vm($def, $skel) {
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags);
if (isset($m[8])) {
$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[8]);
if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
}
if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
}
}
$opnames[$op] = $code;
$handler = $code;
Expand Down
4 changes: 3 additions & 1 deletion Zend/zend_vm_opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#define ZEND_VM_EXT_ARG_NUM 0x00040000
#define ZEND_VM_EXT_ARRAY_INIT 0x00080000
#define ZEND_VM_EXT_REF 0x00100000
#define ZEND_VM_EXT_MASK 0xff000000
#define ZEND_VM_EXT_MASK 0x0f000000
#define ZEND_VM_EXT_NUM 0x01000000
#define ZEND_VM_EXT_JMP_ADDR 0x03000000
#define ZEND_VM_EXT_DIM_OBJ 0x04000000
Expand All @@ -58,6 +58,8 @@
#define ZEND_VM_EXT_FAST_RET 0x0a000000
#define ZEND_VM_EXT_SRC 0x0b000000
#define ZEND_VM_EXT_SEND 0x0c000000
#define ZEND_VM_NO_CONST_CONST 0x40000000
#define ZEND_VM_COMMUTATIVE 0x80000000
#define ZEND_VM_OP1_FLAGS(flags) (flags & 0xff)
#define ZEND_VM_OP2_FLAGS(flags) ((flags >> 8) & 0xff)

Expand Down

0 comments on commit 7f80514

Please sign in to comment.