/lib/JIT/Helper.php

https://github.com/ircmaxell/php-compiler · PHP · 460 lines · 442 code · 10 blank · 8 comment · 5 complexity · 32a235b74c86692e0fc1918a260c798a MD5 · raw file

  1. <?php
  2. # This file is generated, changes you make will be lost.
  3. # Make your changes in /compiler/lib/JIT/Helper.pre instead.
  4. /*
  5. * This file is part of PHP-Compiler, a PHP CFG Compiler for PHP code
  6. *
  7. * @copyright 2015 Anthony Ferrara. All rights reserved
  8. * @license MIT See LICENSE at the root of the project for more info
  9. */
  10. namespace PHPCompiler\JIT;
  11. use PHPCompiler\OpCode;
  12. use PHPLLVM;
  13. use PHPLLVM\Builder;
  14. class Helper {
  15. public Context $context;
  16. public function __construct(Context $context) {
  17. $this->context = $context;
  18. }
  19. public function unaryOp(OpCode $opcode, Variable $var): Variable {
  20. $varValue = $this->loadValue($var);
  21. switch ($var->type) {
  22. case Variable::TYPE_NATIVE_LONG:
  23. switch ($opcode->type) {
  24. case OpCode::TYPE_UNARY_MINUS:
  25. $result = $this->context->builder->negate($varValue);
  26. goto return_long;
  27. }
  28. break;
  29. case Variable::TYPE_NATIVE_DOUBLE:
  30. switch ($opcode->type) {
  31. case OpCode::TYPE_UNARY_MINUS:
  32. $result = $this->context->builder->fNegate($varValue);
  33. goto return_double;
  34. }
  35. break;
  36. }
  37. $type = $opcode->getType();
  38. throw new \LogicException("Reached end of switch, can't handle unary operation yet: $type for type {$var->type}");
  39. return_double:
  40. return new Variable($this->context, Variable::TYPE_NATIVE_DOUBLE, Variable::KIND_VALUE, $result);
  41. return_long:
  42. return new Variable($this->context, Variable::TYPE_NATIVE_LONG, Variable::KIND_VALUE, $result);
  43. return_bool:
  44. return new Variable($this->context, Variable::TYPE_NATIVE_BOOL, Variable::KIND_VALUE, $result);
  45. }
  46. public function binaryOp(OpCode $opcode, Variable $left, Variable $right): Variable {
  47. $leftValue = $this->loadValue($left);
  48. $rightValue = $this->loadValue($right);
  49. $leftType = $left->type;
  50. $rightType = $right->type;
  51. restart:
  52. switch (type_pair($leftType, $rightType)) {
  53. case TYPE_PAIR_NATIVE_LONG_NATIVE_DOUBLE:
  54. $leftType = Variable::TYPE_NATIVE_DOUBLE;
  55. $leftValue = $this->context->builder->siToFp($leftValue, $rightValue->typeOf());
  56. goto restart;
  57. case TYPE_PAIR_NATIVE_DOUBLE_NATIVE_LONG:
  58. $rightType = Variable::TYPE_NATIVE_DOUBLE;
  59. $rightValue = $this->context->builder->siToFp($rightValue, $leftValue->typeOf());
  60. goto restart;
  61. case TYPE_PAIR_NATIVE_DOUBLE_NATIVE_DOUBLE:
  62. switch ($opcode->type) {
  63. case OpCode::TYPE_MUL:
  64. $result = $this->context->builder->fmul($leftValue, $rightValue);
  65. goto return_double;
  66. case OpCode::TYPE_PLUS:
  67. $result = $this->context->builder->fadd($leftValue, $rightValue);
  68. goto return_double;
  69. case OpCode::TYPE_MINUS:
  70. $result = $this->context->builder->fsub($leftValue, $rightValue);
  71. goto return_double;
  72. case OpCode::TYPE_DIV:
  73. $result = $this->context->builder->fdiv($leftValue, $rightValue);
  74. goto return_double;
  75. case OpCode::TYPE_MODULO:
  76. $result = $this->context->builder->frem($leftValue, $rightValue);
  77. goto return_double;
  78. case OpCode::TYPE_BITWISE_AND:
  79. case OpCode::TYPE_BITWISE_OR:
  80. case OpCode::TYPE_BITWISE_XOR:
  81. break;
  82. case OpCode::TYPE_GREATER_OR_EQUAL:
  83. $result = $this->context->builder->fcmp(Builder::REAL_OGE, $leftValue, $rightValue);
  84. goto return_bool;
  85. case OpCode::TYPE_SMALLER_OR_EQUAL:
  86. $result = $this->context->builder->fcmp(Builder::REAL_OLE, $leftValue, $rightValue);
  87. goto return_bool;
  88. case OpCode::TYPE_GREATER:
  89. $result = $this->context->builder->fcmp(Builder::REAL_OGT, $leftValue, $rightValue);
  90. goto return_bool;
  91. case OpCode::TYPE_SMALLER:
  92. $result = $this->context->builder->fcmp(Builder::REAL_OLT, $leftValue, $rightValue);
  93. goto return_bool;
  94. case OpCode::TYPE_IDENTICAL:
  95. case OpCode::TYPE_EQUAL:
  96. $result = $this->context->builder->fcmp(Builder::REAL_OEQ, $leftValue, $rightValue);
  97. goto return_bool;
  98. case OpCode::TYPE_NOT_EQUAL:
  99. $result = $this->context->builder->fcmp(Builder::REAL_ONE, $leftValue, $rightValue);
  100. goto return_bool;
  101. }
  102. break;
  103. case TYPE_PAIR_NATIVE_LONG_NATIVE_LONG:
  104. switch ($opcode->type) {
  105. case OpCode::TYPE_MUL:
  106. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  107. $result = $this->context->builder->mulNoSignedWrap($leftValue, $__right);
  108. goto return_long;
  109. case OpCode::TYPE_PLUS:
  110. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  111. $result = $this->context->builder->addNoSignedWrap($leftValue, $__right);
  112. goto return_long;
  113. case OpCode::TYPE_MINUS:
  114. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  115. $result = $this->context->builder->subNoSignedWrap($leftValue, $__right);
  116. goto return_long;
  117. case OpCode::TYPE_DIV:
  118. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  119. $result = $this->context->builder->signedDiv($leftValue, $__right);
  120. goto return_long;
  121. case OpCode::TYPE_MODULO:
  122. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  123. $result = $this->context->builder->signedRem($leftValue, $__right);
  124. goto return_long;
  125. case OpCode::TYPE_BITWISE_AND:
  126. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  127. $result = $this->context->builder->bitwiseAnd($leftValue, $__right);
  128. goto return_long;
  129. case OpCode::TYPE_BITWISE_OR:
  130. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  131. $result = $this->context->builder->bitwiseOr($leftValue, $__right);
  132. goto return_long;
  133. case OpCode::TYPE_BITWISE_XOR:
  134. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  135. $result = $this->context->builder->bitwiseXor($leftValue, $__right);
  136. goto return_long;
  137. case OpCode::TYPE_GREATER_OR_EQUAL:
  138. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  139. $cmp = \PHPLLVM\Builder::INT_SGE;
  140. $result = $this->context->builder->icmp($cmp, $leftValue, $__right);
  141. goto return_bool;
  142. case OpCode::TYPE_SMALLER_OR_EQUAL:
  143. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  144. $cmp = \PHPLLVM\Builder::INT_SLE;
  145. $result = $this->context->builder->icmp($cmp, $leftValue, $__right);
  146. goto return_bool;
  147. case OpCode::TYPE_GREATER:
  148. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  149. $cmp = \PHPLLVM\Builder::INT_SGT;
  150. $result = $this->context->builder->icmp($cmp, $leftValue, $__right);
  151. goto return_bool;
  152. case OpCode::TYPE_SMALLER:
  153. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  154. $cmp = \PHPLLVM\Builder::INT_SLT;
  155. $result = $this->context->builder->icmp($cmp, $leftValue, $__right);
  156. goto return_bool;
  157. case OpCode::TYPE_IDENTICAL:
  158. case OpCode::TYPE_EQUAL:
  159. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  160. $result = $this->context->builder->icmp(\PHPLLVM\Builder::INT_EQ, $leftValue, $__right);
  161. goto return_bool;
  162. case OpCode::TYPE_NOT_EQUAL:
  163. $__right = $this->context->builder->intCast($rightValue, $leftValue->typeOf());
  164. $result = $this->context->builder->icmp(\PHPLLVM\Builder::INT_NE, $leftValue, $__right);
  165. goto return_bool;
  166. }
  167. break;
  168. }
  169. $type = $opcode->getType();
  170. throw new \LogicException("Reached end of switch, can't handle binary operation yet: $type for type pair {$leftType} and {$rightType}");
  171. return_double:
  172. return new Variable($this->context, Variable::TYPE_NATIVE_DOUBLE, Variable::KIND_VALUE, $result);
  173. return_long:
  174. return new Variable($this->context, Variable::TYPE_NATIVE_LONG, Variable::KIND_VALUE, $result);
  175. return_bool:
  176. return new Variable($this->context, Variable::TYPE_NATIVE_BOOL, Variable::KIND_VALUE, $result);
  177. }
  178. public function loadValue(Variable $variable): PHPLLVM\Value {
  179. if ($variable->kind === Variable::KIND_VALUE) {
  180. return $variable->value;
  181. }
  182. return $this->context->builder->load($variable->value);
  183. }
  184. }