Skip to content

Commit

Permalink
Implement the rest of the unboxed unary operations
Browse files Browse the repository at this point in the history
  • Loading branch information
tonybaloney committed Nov 12, 2021
1 parent 7bf755f commit 20e3b04
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 14 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

* Added unboxed integer operations for BINARY_LSHIFT, BINARY_RSHIFT, BINARY_AND, BINARY_OR, BINARY_XOR
* BINARY_MULTIPLY and BINARY_POWER will stay unboxed if the right-hand operator is a constant that won't overflow (e.g. x ** 2)
* Added unboxed UNARY_NOT operation for float, bool and int types
* Added unboxed UNARY_NOT,UNARY_POSITIVE and UNARY_NEGATIVE operation for float, bool and int types
* Added unboxed UNARY_INVERY for int and bool types
* The types of global variables are profiled at compile-time
* Improved performance of bytearrays, by adding an unboxed bytearray type and unboxed slice operations for bytearrays, yielding unboxed integers
* Fixed a reference count bug with unboxed range iterators
Expand Down
16 changes: 16 additions & 0 deletions Tests/test_math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,16 @@ TEST_CASE("test binary/arithmetic operations") {
"def f():\n x = 1.0\n y = +x\n return y");
CHECK(t.returns() == "1.0");
}
SECTION("int postive unary") {
auto t = EmissionTest(
"def f():\n x = -2\n y = +x\n return y");
CHECK(t.returns() == "2");
}
SECTION("int postive unary positive const") {
auto t = EmissionTest(
"def f():\n x = 2\n y = +x\n return y");
CHECK(t.returns() == "2");
}
SECTION("float not unary") {
auto t = EmissionTest(
"def f():\n x = 1.0\n if not x:\n return 1\n return 2");
Expand All @@ -842,6 +852,12 @@ TEST_CASE("test binary/arithmetic operations") {
"def f():\n x = 1.0\n y = not x\n return y");
CHECK(t.returns() == "False");
}
SECTION("int ~ operator") {
CHECK(EmissionTest("def f():\n x = -1\n return ~x").returns() == "0");
CHECK(EmissionTest("def f():\n x = -4\n return ~x").returns() == "3");
CHECK(EmissionTest("def f():\n x = 4\n return ~x").returns() == "-5");
CHECK(EmissionTest("def f():\n x = 0\n return ~x").returns() == "-1");
}
SECTION("test unary constants") {
auto t = EmissionTest(
"def f(): \n"
Expand Down
40 changes: 27 additions & 13 deletions src/pyjion/absint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1993,22 +1993,30 @@ AbstactInterpreterCompileResult AbstractInterpreter::compileWorker(PgcStatus pgc
buildSet(oparg);
break;
case UNARY_POSITIVE:
m_comp->emit_unary_positive();
decStack();
errorCheck("unary positive failed", "", opcodeIndex);
incStack();
if (CAN_UNBOX() && op.escape) {
m_comp->emit_unboxed_unary_positive(stackInfo.top());
} else {
m_comp->emit_unary_positive();
decStack();
errorCheck("unary positive failed", "", opcodeIndex);
incStack();
}
break;
case UNARY_NEGATIVE:
m_comp->emit_unary_negative();
decStack();
errorCheck("unary negative failed", "", opcodeIndex);
incStack();
if (CAN_UNBOX() && op.escape) {
m_comp->emit_unboxed_unary_negative(stackInfo.top());
} else {
m_comp->emit_unary_negative();
decStack();
errorCheck("unary negative failed", "", opcodeIndex);
incStack();
}
break;
case UNARY_NOT:
if (CAN_UNBOX() && op.escape) {
m_comp->emit_unboxed_unary_not(stackInfo.top());
decStack(1);
incStack(1, LK_Bool);
incStack(1, LK_Int);
} else {
m_comp->emit_unary_not();
decStack(1);
Expand All @@ -2017,10 +2025,16 @@ AbstactInterpreterCompileResult AbstractInterpreter::compileWorker(PgcStatus pgc
}
break;
case UNARY_INVERT:
m_comp->emit_unary_invert();
decStack(1);
errorCheck("unary invert failed", "", op.index);
incStack();
if (CAN_UNBOX() && op.escape) {
m_comp->emit_unboxed_unary_invert(stackInfo.top());
decStack(1);
incStack(1, LK_Int);
} else {
m_comp->emit_unary_invert();
decStack(1);
errorCheck("unary invert failed", "", op.index);
incStack();
}
break;
case BINARY_SUBSCR:
if (CAN_UNBOX() && op.escape) {
Expand Down
3 changes: 3 additions & 0 deletions src/pyjion/ipycomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@ class IPythonCompiler {
virtual void emit_unary_invert() = 0;

virtual void emit_unboxed_unary_not(AbstractValueWithSources val) = 0;
virtual void emit_unboxed_unary_positive(AbstractValueWithSources val) = 0;
virtual void emit_unboxed_unary_negative(AbstractValueWithSources val) = 0;
virtual void emit_unboxed_unary_invert(AbstractValueWithSources val) = 0;

// Performans a binary operation for values on the stack which are unboxed floating points
virtual LocalKind emit_binary_float(uint16_t opcode) = 0;
Expand Down
70 changes: 70 additions & 0 deletions src/pyjion/pycomp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2571,6 +2571,76 @@ void PythonCompiler::emit_unboxed_unary_not(AbstractValueWithSources val) {
}
}

void PythonCompiler::emit_unboxed_unary_positive(AbstractValueWithSources val) {
#ifdef DEBUG
assert(supportsEscaping(val.Value->kind()));
#endif
switch (val.Value->kind()){
case AVK_Bool:
break; // Do nothing
case AVK_Integer: {
Local loc = emit_define_local(LK_Int), mask = emit_define_local(LK_Int);
emit_store_local(loc);
emit_load_local(loc);
emit_int(63);
m_il.rshift();
emit_store_local(mask);

emit_load_local(loc);
emit_load_local(mask);
m_il.add();
emit_load_local(mask);
m_il.bitwise_xor();
emit_free_local(loc);
emit_free_local(mask);
}
break;
case AVK_Float: {
// TODO : Write a more efficient branch-less version
Label is_positive = emit_define_label();
m_il.dup();
m_il.ld_r8(0.0);
emit_branch(BranchGreaterThanEqual, is_positive);
m_il.neg();
emit_mark_label(is_positive);
}
break;
default:
throw UnexpectedValueException();
}
}

void PythonCompiler::emit_unboxed_unary_negative(AbstractValueWithSources val) {
#ifdef DEBUG
assert(supportsEscaping(val.Value->kind()));
#endif
switch (val.Value->kind()){
case AVK_Integer:
case AVK_Bool:
case AVK_Float:
m_il.neg();
break;
default:
throw UnexpectedValueException();
}
}

void PythonCompiler::emit_unboxed_unary_invert(AbstractValueWithSources val) {
#ifdef DEBUG
assert(supportsEscaping(val.Value->kind()));
#endif
switch (val.Value->kind()){
case AVK_Integer:
case AVK_Bool:
m_il.ld_i4(1);
m_il.add();
m_il.neg();
break;
default:
throw UnexpectedValueException();
}
}

void PythonCompiler::emit_infinity() {
m_il.ld_r8(INFINITY);
}
Expand Down
3 changes: 3 additions & 0 deletions src/pyjion/pycomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,9 @@ class PythonCompiler : public IPythonCompiler {
void emit_unary_not() override;
void emit_unary_invert() override;
void emit_unboxed_unary_not(AbstractValueWithSources val) override;
void emit_unboxed_unary_positive(AbstractValueWithSources val) override;
void emit_unboxed_unary_negative(AbstractValueWithSources val) override;
void emit_unboxed_unary_invert(AbstractValueWithSources val) override;

void emit_import_name(void* name) override;
void emit_import_from(void* name) override;
Expand Down
3 changes: 3 additions & 0 deletions src/pyjion/unboxing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ bool supportsUnboxing(py_opcode opcode) {
case BINARY_OR:
case BINARY_XOR:
case UNARY_NOT:
case UNARY_POSITIVE:
case UNARY_NEGATIVE:
case UNARY_INVERT:
return true;
default:
return false;
Expand Down

0 comments on commit 20e3b04

Please sign in to comment.