Commit 2d55194c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add int->long promotion on overflow

This commit is a straightforward implementation that doesn't include
any speculation-like optimizations.  For operations that can overflow,
just relax the type-return-specification to UNKNOWN, and do the overflow
checks in the runtime.  This means that we no longer emit fast native
integer instructions even if we know operands are ints.

Will have to add optimizations:
- range analysis so that we can know there won't be overflow
- deopt-on-overflow so that we can work with unboxed ints even if there's potential overflow
parent 0a7dc330
...@@ -734,6 +734,7 @@ public: ...@@ -734,6 +734,7 @@ public:
} }
virtual CompilerType* getattrType(const std::string* attr, bool cls_only) { virtual CompilerType* getattrType(const std::string* attr, bool cls_only) {
/*
static std::vector<AbstractFunctionType::Sig*> sigs; static std::vector<AbstractFunctionType::Sig*> sigs;
if (sigs.size() == 0) { if (sigs.size() == 0) {
AbstractFunctionType::Sig* int_sig = new AbstractFunctionType::Sig(); AbstractFunctionType::Sig* int_sig = new AbstractFunctionType::Sig();
...@@ -758,6 +759,7 @@ public: ...@@ -758,6 +759,7 @@ public:
|| *attr == "__ifloordiv__" || *attr == "__iand__" || *attr == "__ior__" || *attr == "__ixor__") { || *attr == "__ifloordiv__" || *attr == "__iand__" || *attr == "__ior__" || *attr == "__ixor__") {
return AbstractFunctionType::get(sigs); return AbstractFunctionType::get(sigs);
} }
*/
return BOXED_INT->getattrType(attr, cls_only); return BOXED_INT->getattrType(attr, cls_only);
} }
...@@ -828,7 +830,8 @@ public: ...@@ -828,7 +830,8 @@ public:
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs, CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override { AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
if (rhs->getType() != INT) { bool can_lower = (rhs->getType() == INT && exp_type == Compare);
if (!can_lower) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT); ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type); CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter); converted->decvref(emitter);
...@@ -837,7 +840,7 @@ public: ...@@ -837,7 +840,7 @@ public:
ConcreteCompilerVariable* converted_right = rhs->makeConverted(emitter, INT); ConcreteCompilerVariable* converted_right = rhs->makeConverted(emitter, INT);
llvm::Value* v; llvm::Value* v;
if (op_type == AST_TYPE::Mod) { /*if (op_type == AST_TYPE::Mod) {
v = emitter.createCall2(info.exc_info, g.funcs.mod_i64_i64, var->getValue(), converted_right->getValue()) v = emitter.createCall2(info.exc_info, g.funcs.mod_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction(); .getInstruction();
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) { } else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) {
...@@ -879,7 +882,7 @@ public: ...@@ -879,7 +882,7 @@ public:
break; break;
} }
v = emitter.getBuilder()->CreateBinOp(binopcode, var->getValue(), converted_right->getValue()); v = emitter.getBuilder()->CreateBinOp(binopcode, var->getValue(), converted_right->getValue());
} else { } else */ {
assert(exp_type == Compare); assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred; llvm::CmpInst::Predicate cmp_pred;
switch (op_type) { switch (op_type) {
......
...@@ -152,8 +152,8 @@ public: ...@@ -152,8 +152,8 @@ public:
static void handle_sigfpe(int signum) { static void handle_sigfpe(int signum) {
assert(signum == SIGFPE); assert(signum == SIGFPE);
fprintf(stderr, "ZeroDivisionError: integer division or modulo by zero\n"); fprintf(stderr, "SIGFPE!\n");
exit(1); abort();
} }
void initCodegen() { void initCodegen() {
...@@ -226,7 +226,7 @@ void initCodegen() { ...@@ -226,7 +226,7 @@ void initCodegen() {
setupRuntime(); setupRuntime();
signal(SIGFPE, &handle_sigfpe); // signal(SIGFPE, &handle_sigfpe);
// There are some parts of llvm that are only configurable through command line args, // There are some parts of llvm that are only configurable through command line args,
// so construct a fake argc/argv pair and pass it to the llvm command line machinery: // so construct a fake argc/argv pair and pass it to the llvm command line machinery:
......
...@@ -650,8 +650,8 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -650,8 +650,8 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
args[0].n, args[1].d, args[2].d, args[3].n); args[0].n, args[1].d, args[2].d, args[3].n);
break; break;
case 0b101010: case 0b101010:
r = reinterpret_cast<int64_t (*)(double, int, double, int64_t)>(f)(args[0].d, args[1].n, r = reinterpret_cast<int64_t (*)(double, int64_t, double, int64_t)>(f)(
args[2].d, args[3].n); args[0].d, args[1].n, args[2].d, args[3].n);
break; break;
case 0b1000000: // 64 case 0b1000000: // 64
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t)>(f)( r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
......
...@@ -234,10 +234,6 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -234,10 +234,6 @@ void initGlobalFuncs(GlobalState& g) {
GET(raise0); GET(raise0);
GET(raise3); GET(raise3);
g.funcs.div_i64_i64 = getFunc((void*)div_i64_i64, "div_i64_i64");
g.funcs.mod_i64_i64 = getFunc((void*)mod_i64_i64, "mod_i64_i64");
g.funcs.pow_i64_i64 = getFunc((void*)pow_i64_i64, "pow_i64_i64");
GET(div_float_float); GET(div_float_float);
GET(mod_float_float); GET(mod_float_float);
GET(pow_float_float); GET(pow_float_float);
......
...@@ -47,7 +47,6 @@ struct GlobalFuncs { ...@@ -47,7 +47,6 @@ struct GlobalFuncs {
llvm::Value* __cxa_begin_catch, *__cxa_end_catch; llvm::Value* __cxa_begin_catch, *__cxa_end_catch;
llvm::Value* raise0, *raise3; llvm::Value* raise0, *raise3;
llvm::Value* div_i64_i64, *mod_i64_i64, *pow_i64_i64;
llvm::Value* div_float_float, *mod_float_float, *pow_float_float; llvm::Value* div_float_float, *mod_float_float, *pow_float_float;
}; };
} }
......
...@@ -27,6 +27,10 @@ ...@@ -27,6 +27,10 @@
#define STACK_GROWS_DOWN 1 #define STACK_GROWS_DOWN 1
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#define _STRINGIFY(N) #N #define _STRINGIFY(N) #N
#define STRINGIFY(N) _STRINGIFY(N) #define STRINGIFY(N) _STRINGIFY(N)
#define _CAT(A, B) A##B #define _CAT(A, B) A##B
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/gc_runtime.h" #include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h" #include "runtime/inline/boxing.h"
#include "runtime/int.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
...@@ -93,6 +94,8 @@ void setupSys() { ...@@ -93,6 +94,8 @@ void setupSys() {
sys_module->giveAttr("hexversion", boxInt(0x01000000 * PYTHON_VERSION_MAJOR + 0x010000 * PYTHON_VERSION_MINOR sys_module->giveAttr("hexversion", boxInt(0x01000000 * PYTHON_VERSION_MAJOR + 0x010000 * PYTHON_VERSION_MINOR
+ 0x0100 * PYTHON_VERSION_MICRO)); + 0x0100 * PYTHON_VERSION_MICRO));
sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX));
} }
void setupSysEnd() { void setupSysEnd() {
......
This diff is collapsed.
...@@ -15,21 +15,25 @@ ...@@ -15,21 +15,25 @@
#ifndef PYSTON_RUNTIME_INT_H #ifndef PYSTON_RUNTIME_INT_H
#define PYSTON_RUNTIME_INT_H #define PYSTON_RUNTIME_INT_H
#include <climits>
#include "core/common.h" #include "core/common.h"
#include "runtime/types.h" #include "runtime/types.h"
namespace pyston { namespace pyston {
extern "C" i64 div_i64_i64(i64 lhs, i64 rhs) ALWAYSINLINE; // These should probably be defined wherever we define the object-representation functions:
extern "C" i64 div_i64_i64(i64 lhs, i64 rhs); static_assert(sizeof(int64_t) == sizeof(long), "");
extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs) ALWAYSINLINE; #define PYSTON_INT_MIN LONG_MIN
#define PYSTON_INT_MAX LONG_MAX
extern "C" Box* div_i64_i64(i64 lhs, i64 rhs);
extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs); extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs);
extern "C" i64 add_i64_i64(i64 lhs, i64 rhs) ALWAYSINLINE; extern "C" Box* add_i64_i64(i64 lhs, i64 rhs);
extern "C" i64 add_i64_i64(i64 lhs, i64 rhs); extern "C" Box* sub_i64_i64(i64 lhs, i64 rhs);
extern "C" i64 sub_i64_i64(i64 lhs, i64 rhs); extern "C" Box* pow_i64_i64(i64 lhs, i64 rhs);
extern "C" i64 pow_i64_i64(i64 lhs, i64 rhs); extern "C" Box* mul_i64_i64(i64 lhs, i64 rhs);
extern "C" i64 mul_i64_i64(i64 lhs, i64 rhs);
extern "C" i1 eq_i64_i64(i64 lhs, i64 rhs); extern "C" i1 eq_i64_i64(i64 lhs, i64 rhs);
extern "C" i1 ne_i64_i64(i64 lhs, i64 rhs); extern "C" i1 ne_i64_i64(i64 lhs, i64 rhs);
extern "C" i1 lt_i64_i64(i64 lhs, i64 rhs); extern "C" i1 lt_i64_i64(i64 lhs, i64 rhs);
......
...@@ -42,6 +42,12 @@ extern "C" Box* createLong(const std::string* s) { ...@@ -42,6 +42,12 @@ extern "C" Box* createLong(const std::string* s) {
return rtn; return rtn;
} }
extern "C" BoxedLong* boxLong(int64_t n) {
BoxedLong* rtn = new BoxedLong(long_cls);
mpz_init_set_si(rtn->n, n);
return rtn;
}
extern "C" Box* longNew(Box* _cls, Box* val) { extern "C" Box* longNew(Box* _cls, Box* val) {
if (!isSubclass(_cls->cls, type_cls)) if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "long.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str()); raiseExcHelper(TypeError, "long.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str());
...@@ -99,6 +105,49 @@ Box* longStr(BoxedLong* v) { ...@@ -99,6 +105,49 @@ Box* longStr(BoxedLong* v) {
return rtn; return rtn;
} }
Box* longNeg(BoxedLong* v1) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__neg__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
BoxedLong* r = new BoxedLong(long_cls);
mpz_init(r->n);
mpz_neg(r->n, v1->n);
return r;
}
Box* longAdd(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__add__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (!isSubclass(_v2->cls, long_cls))
return NotImplemented;
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
BoxedLong* r = new BoxedLong(long_cls);
mpz_init(r->n);
mpz_add(r->n, v1->n, v2->n);
return r;
}
Box* longSub(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__sub__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (!isSubclass(_v2->cls, long_cls))
return NotImplemented;
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
BoxedLong* r = new BoxedLong(long_cls);
mpz_init(r->n);
mpz_sub(r->n, v1->n, v2->n);
return r;
}
Box* longMul(BoxedLong* v1, Box* _v2) { Box* longMul(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls)) if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__mul__' requires a 'long' object but received a '%s'", raiseExcHelper(TypeError, "descriptor '__mul__' requires a 'long' object but received a '%s'",
...@@ -115,6 +164,46 @@ Box* longMul(BoxedLong* v1, Box* _v2) { ...@@ -115,6 +164,46 @@ Box* longMul(BoxedLong* v1, Box* _v2) {
return r; return r;
} }
Box* longDiv(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__div__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (!isSubclass(_v2->cls, long_cls))
return NotImplemented;
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
if (mpz_cmp_si(v2->n, 0) == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
BoxedLong* r = new BoxedLong(long_cls);
mpz_init(r->n);
// It looks like the 'f'-family of integer functions ("floor") do the Python-style rounding
mpz_fdiv_q(r->n, v1->n, v2->n);
return r;
}
Box* longPow(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (!isSubclass(_v2->cls, long_cls))
return NotImplemented;
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
RELEASE_ASSERT(mpz_sgn(v2->n) >= 0, "");
RELEASE_ASSERT(mpz_fits_ulong_p(v2->n), "");
uint64_t n2 = mpz_get_ui(v2->n);
BoxedLong* r = new BoxedLong(long_cls);
mpz_init(r->n);
mpz_pow_ui(r->n, v1->n, n2);
return r;
}
void setupLong() { void setupLong() {
long_cls->giveAttr("__name__", boxStrConstant("long")); long_cls->giveAttr("__name__", boxStrConstant("long"));
...@@ -122,6 +211,7 @@ void setupLong() { ...@@ -122,6 +211,7 @@ void setupLong() {
new BoxedFunction(boxRTFunction((void*)longNew, UNKNOWN, 2, 1, false, false), { boxInt(0) })); new BoxedFunction(boxRTFunction((void*)longNew, UNKNOWN, 2, 1, false, false), { boxInt(0) }));
long_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)longMul, UNKNOWN, 2))); long_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)longMul, UNKNOWN, 2)));
long_cls->giveAttr("__div__", new BoxedFunction(boxRTFunction((void*)longDiv, UNKNOWN, 2)));
long_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)longRepr, STR, 1))); long_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)longRepr, STR, 1)));
long_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)longStr, STR, 1))); long_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)longStr, STR, 1)));
......
...@@ -35,6 +35,15 @@ public: ...@@ -35,6 +35,15 @@ public:
}; };
extern "C" Box* createLong(const std::string* s); extern "C" Box* createLong(const std::string* s);
extern "C" BoxedLong* boxLong(int64_t n);
Box* longNeg(BoxedLong* lhs);
Box* longAdd(BoxedLong* lhs, Box* rhs);
Box* longSub(BoxedLong* lhs, Box* rhs);
Box* longMul(BoxedLong* lhs, Box* rhs);
Box* longDiv(BoxedLong* lhs, Box* rhs);
Box* longPow(BoxedLong* lhs, Box* rhs);
} }
#endif #endif
import sys
i = sys.maxint
print "maxint:", repr(i)
print "maxint + 1:", repr(i+1)
print "maxint * 1:", repr(i*1)
print "maxint * 2", repr(i*2)
print "maxint - -1:", repr(i - (-1))
print "-maxint:", repr(-i)
j = (-i-1)
print "-maxint-1 [aka minint]:", repr(j)
print "minint + 1:", repr(j+1)
print "minint - 1:", repr(j-1)
print "-minint:", repr(-j)
print "minint * -1:", repr(j * (-1))
print "minint / -1:", repr(j / (-1))
print "2 ** 100:", 2 ** 100
...@@ -6,3 +6,8 @@ t = 1L ...@@ -6,3 +6,8 @@ t = 1L
for i in xrange(150): for i in xrange(150):
t *= l t *= l
print t, repr(t) print t, repr(t)
print 1L / 5L
print -1L / 5L
print 1L / -5L
print -1L / -5L
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment