Commit 423f0a7a authored by Kevin Modzelewski's avatar Kevin Modzelewski

Move binexp handling into the type-specific behavior

Before it was part of the (type-agnostic) AST-walker, which didn't make sense.
parent 894578a0
......@@ -288,6 +288,55 @@ public:
converted_slice->decvref(emitter);
return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType());
llvm::Value* rtn;
bool do_patchpoint = ENABLE_ICBINEXPS && !info.isInterpreted();
llvm::Value* rt_func;
void* rt_func_addr;
if (exp_type == BinOp) {
rt_func = g.funcs.binop;
rt_func_addr = (void*)binop;
} else if (exp_type == AugBinOp) {
rt_func = g.funcs.augbinop;
rt_func_addr = (void*)augbinop;
} else {
rt_func = g.funcs.compare;
rt_func_addr = (void*)compare;
}
if (do_patchpoint) {
PatchpointSetupInfo* pp
= patchpoints::createBinexpPatchpoint(emitter.currentFunction(), info.getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(var->getValue());
llvm_args.push_back(converted_rhs->getValue());
llvm_args.push_back(getConstantInt(op_type, g.i32));
llvm::Value* uncasted
= emitter.createPatchpoint(pp, rt_func_addr, llvm_args, info.exc_info).getInstruction();
rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
} else {
rtn = emitter.createCall3(info.exc_info, rt_func, var->getValue(), converted_rhs->getValue(),
getConstantInt(op_type, g.i32)).getInstruction();
}
converted_rhs->decvref(emitter);
if (op_type == AST_TYPE::In || op_type == AST_TYPE::NotIn || op_type == AST_TYPE::Is
|| op_type == AST_TYPE::IsNot) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxBool, rtn);
ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(BOOL, unboxed, true);
return rtn;
}
return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
}
};
ConcreteCompilerType* UNKNOWN = new UnknownType();
......@@ -746,6 +795,95 @@ public:
return new ConcreteCompilerVariable(BOOL, cmp, true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
if (rhs->getType() != INT) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* converted_right = rhs->makeConverted(emitter, INT);
llvm::Value* v;
if (op_type == AST_TYPE::Mod) {
v = emitter.createCall2(info.exc_info, g.funcs.mod_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(info.exc_info, g.funcs.div_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (op_type == AST_TYPE::Pow) {
v = emitter.createCall2(info.exc_info, g.funcs.pow_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (op_type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::Add;
break;
case AST_TYPE::BitAnd:
binopcode = llvm::Instruction::And;
break;
case AST_TYPE::BitOr:
binopcode = llvm::Instruction::Or;
break;
case AST_TYPE::BitXor:
binopcode = llvm::Instruction::Xor;
break;
case AST_TYPE::LShift:
binopcode = llvm::Instruction::Shl;
break;
case AST_TYPE::RShift:
binopcode = llvm::Instruction::AShr;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::Mul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::Sub;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateBinOp(binopcode, var->getValue(), converted_right->getValue());
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (op_type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::ICMP_EQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::ICMP_SLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::ICMP_SLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::ICMP_SGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::ICMP_SGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::ICMP_NE;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateICmp(cmp_pred, var->getValue(), converted_right->getValue());
}
converted_right->decvref(emitter);
assert(v->getType() == g.i64 || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.i64 ? INT : BOOL, v, true);
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_INT; }
} _INT;
ConcreteCompilerType* INT = &_INT;
......@@ -840,6 +978,110 @@ public:
llvm::Value* cmp = emitter.getBuilder()->CreateFCmpUNE(var->getValue(), llvm::ConstantFP::get(g.double_, 0));
return new ConcreteCompilerVariable(BOOL, cmp, true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
if (rhs->getType() != INT && rhs->getType() != FLOAT) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_FLOAT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* converted_right;
if (rhs->getType() == FLOAT) {
converted_right = rhs->makeConverted(emitter, FLOAT);
} else {
converted_right = rhs->makeConverted(emitter, INT);
llvm::Value* conv = emitter.getBuilder()->CreateSIToFP(converted_right->getValue(), g.double_);
converted_right->decvref(emitter);
converted_right = new ConcreteCompilerVariable(FLOAT, conv, true);
}
llvm::Value* v;
bool succeeded = true;
if (op_type == AST_TYPE::Mod) {
v = emitter.createCall2(info.exc_info, g.funcs.mod_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(info.exc_info, g.funcs.div_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::Pow) {
v = emitter.createCall2(info.exc_info, g.funcs.pow_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (op_type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::FAdd;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::FMul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::FSub;
break;
case AST_TYPE::BitAnd:
case AST_TYPE::BitOr:
case AST_TYPE::BitXor:
case AST_TYPE::LShift:
case AST_TYPE::RShift:
succeeded = false;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
if (succeeded) {
v = emitter.getBuilder()->CreateBinOp(binopcode, var->getValue(), converted_right->getValue());
}
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (op_type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::FCMP_OEQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::FCMP_OLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::FCMP_OLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::FCMP_OGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::FCMP_OGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::FCMP_UNE;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateFCmp(cmp_pred, var->getValue(), converted_right->getValue());
}
converted_right->decvref(emitter);
if (succeeded) {
assert(v->getType() == g.double_ || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.double_ ? FLOAT : BOOL, v, true);
}
// TODO duplication with top of function, other functions, etc
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_FLOAT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_FLOAT; }
} _FLOAT;
ConcreteCompilerType* FLOAT = &_FLOAT;
......@@ -1122,6 +1364,31 @@ public:
return rtn;
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType());
BoxedClass* rhs_cls = converted_rhs->guaranteedClass();
if (rhs_cls && rhs_cls->is_constant && !rhs_cls->is_user_defined) {
// Ugly, but for now special-case the set of type-pairs that we know will always work
if (exp_type == BinOp
&& ((cls == int_cls && rhs_cls == int_cls) || (cls == float_cls && rhs_cls == float_cls)
|| (cls == list_cls && rhs_cls == int_cls))) {
const std::string& left_side_name = getOpName(op_type);
ConcreteCompilerVariable* called_constant = tryCallattrConstant(
emitter, info, var, &left_side_name, true, ArgPassSpec(1, 0, 0, 0), { converted_rhs }, NULL, false);
if (called_constant)
return called_constant;
}
}
auto rtn = UNKNOWN->binexp(emitter, info, var, converted_rhs, op_type, exp_type);
converted_rhs->decvref(emitter);
return rtn;
}
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* slice) {
static const std::string attr("__getitem__");
ConcreteCompilerVariable* called_constant
......@@ -1258,6 +1525,14 @@ public:
return rtn;
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) override {
return makeBool(var->getValue()->size() != 0);
}
......@@ -1340,6 +1615,14 @@ public:
return rtn;
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_BOOL; }
};
ConcreteCompilerType* BOOL = new BoolType();
......@@ -1482,6 +1765,14 @@ public:
return BOXED_TUPLE->getattrType(attr, cls_only);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
......@@ -1558,6 +1849,11 @@ public:
return new ConcreteCompilerVariable(BOOL, llvm::UndefValue::get(g.i1), true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
return undefVariable();
}
virtual ConcreteCompilerType* getBoxType() { return UNKNOWN; }
virtual ConcreteCompilerType* getConcreteType() { return this; }
......
......@@ -19,6 +19,7 @@
#include <vector>
#include "codegen/codegen.h"
#include "core/ast.h"
#include "core/types.h"
namespace pyston {
......@@ -47,6 +48,12 @@ public:
typedef std::unordered_map<CompilerVariable*, CompilerVariable*> DupCache;
enum BinExpType {
AugBinOp,
BinOp,
Compare,
};
template <class V> class _ValuedCompilerType : public CompilerType {
public:
typedef ValuedCompilerVariable<V> VAR;
......@@ -63,11 +70,11 @@ public:
printf("getBoxType not defined for %s\n", debugName().c_str());
abort();
}
virtual void drop(IREmitter& emmitter, VAR* value) {
virtual void drop(IREmitter& emmitter, VAR* var) {
printf("drop not defined for %s\n", debugName().c_str());
abort();
}
virtual void grab(IREmitter& emmitter, VAR* value) {
virtual void grab(IREmitter& emmitter, VAR* var) {
printf("grab not defined for %s\n", debugName().c_str());
abort();
}
......@@ -75,53 +82,58 @@ public:
printf("canConvertTo not defined for %s\n", debugName().c_str());
abort();
}
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, VAR* value, ConcreteCompilerType* other_type) {
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, VAR* var, ConcreteCompilerType* other_type) {
printf("makeConverted not defined for %s\n", debugName().c_str());
abort();
}
virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* value) {
virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("nonzero not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr,
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool cls_only) {
printf("getattr not defined for %s\n", debugName().c_str());
abort();
}
virtual void setattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr,
virtual void setattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
CompilerVariable* v) {
printf("setattr not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr,
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
printf("callattr not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* value, struct ArgPassSpec argspec,
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* var, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
printf("call not defined for %s\n", debugName().c_str());
abort();
}
virtual void print(IREmitter& emitter, const OpInfo& info, VAR* value) {
virtual void print(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("print not defined for %s\n", debugName().c_str());
abort();
}
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, VAR* value) {
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("len not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* value, CompilerVariable* v) {
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* v) {
// Can almost do this, except for error messages + types:
// static const std::string attr("__getitem__");
// return callattr(emitter, info, value, &attr, true, ArgPassSpec(1, 0, 0, 0), {v}, NULL);
// return callattr(emitter, info, var, &attr, true, ArgPassSpec(1, 0, 0, 0), {v}, NULL);
printf("getitem not defined for %s\n", debugName().c_str());
abort();
}
virtual llvm::Value* makeClassCheck(IREmitter& emitter, VAR* value, BoxedClass* c) {
virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) {
printf("binexp not defined for %s\n", debugName().c_str());
abort();
}
virtual llvm::Value* makeClassCheck(IREmitter& emitter, VAR* var, BoxedClass* c) {
printf("makeClassCheck not defined for %s\n", debugName().c_str());
abort();
}
......@@ -189,7 +201,7 @@ public:
}
}
void decvref(IREmitter& emitter) {
assert(vrefs > 0 && vrefs < (1 << 20));
ASSERT(vrefs > 0 && vrefs < (1 << 20), "%d", vrefs);
// ASSERT(vrefs, "%s", getType()->debugName().c_str());
vrefs--;
if (vrefs == 0) {
......@@ -229,6 +241,8 @@ public:
virtual void print(IREmitter& emitter, const OpInfo& info) = 0;
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info) = 0;
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable*) = 0;
virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) = 0;
};
template <class V> class ValuedCompilerVariable : public CompilerVariable {
......@@ -299,6 +313,12 @@ public:
CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable* slice) override {
return type->getitem(emitter, info, this, slice);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs, AST_TYPE::AST_TYPE op_type,
BinExpType exp_type) override {
return type->binexp(emitter, info, this, rhs, op_type, exp_type);
}
llvm::Value* makeClassCheck(IREmitter& emitter, BoxedClass* cls) override {
return type->makeClassCheck(emitter, this, cls);
}
......
......@@ -355,11 +355,6 @@ private:
}
}
enum BinExpType {
AugBinOp,
BinOp,
Compare,
};
CompilerVariable* _evalBinExp(AST* node, CompilerVariable* left, CompilerVariable* right, AST_TYPE::AST_TYPE type,
BinExpType exp_type, ExcInfo exc_info) {
assert(state != PARTIAL);
......@@ -367,227 +362,7 @@ private:
assert(left);
assert(right);
if (left->getType() == INT && right->getType() == INT) {
ConcreteCompilerVariable* converted_left = left->makeConverted(emitter, INT);
ConcreteCompilerVariable* converted_right = right->makeConverted(emitter, INT);
llvm::Value* v;
if (type == AST_TYPE::Mod) {
v = emitter.createCall2(exc_info, g.funcs.mod_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Div || type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(exc_info, g.funcs.div_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Pow) {
v = emitter.createCall2(exc_info, g.funcs.pow_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::Add;
break;
case AST_TYPE::BitAnd:
binopcode = llvm::Instruction::And;
break;
case AST_TYPE::BitOr:
binopcode = llvm::Instruction::Or;
break;
case AST_TYPE::BitXor:
binopcode = llvm::Instruction::Xor;
break;
case AST_TYPE::LShift:
binopcode = llvm::Instruction::Shl;
break;
case AST_TYPE::RShift:
binopcode = llvm::Instruction::AShr;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::Mul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::Sub;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateBinOp(binopcode, converted_left->getValue(),
converted_right->getValue());
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::ICMP_EQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::ICMP_SLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::ICMP_SLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::ICMP_SGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::ICMP_SGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::ICMP_NE;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateICmp(cmp_pred, converted_left->getValue(), converted_right->getValue());
}
converted_left->decvref(emitter);
converted_right->decvref(emitter);
assert(v->getType() == g.i64 || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.i64 ? INT : BOOL, v, true);
}
if (left->getType() == FLOAT && (right->getType() == FLOAT || right->getType() == INT)) {
ConcreteCompilerVariable* converted_left = left->makeConverted(emitter, FLOAT);
ConcreteCompilerVariable* converted_right;
if (right->getType() == FLOAT) {
converted_right = right->makeConverted(emitter, FLOAT);
} else {
converted_right = right->makeConverted(emitter, INT);
llvm::Value* conv = emitter.getBuilder()->CreateSIToFP(converted_right->getValue(), g.double_);
converted_right->decvref(emitter);
converted_right = new ConcreteCompilerVariable(FLOAT, conv, true);
}
llvm::Value* v;
bool succeeded = true;
if (type == AST_TYPE::Mod) {
v = emitter.createCall2(exc_info, g.funcs.mod_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Div || type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(exc_info, g.funcs.div_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Pow) {
v = emitter.createCall2(exc_info, g.funcs.pow_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::FAdd;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::FMul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::FSub;
break;
case AST_TYPE::BitAnd:
case AST_TYPE::BitOr:
case AST_TYPE::BitXor:
case AST_TYPE::LShift:
case AST_TYPE::RShift:
succeeded = false;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
if (succeeded) {
v = emitter.getBuilder()->CreateBinOp(binopcode, converted_left->getValue(),
converted_right->getValue());
}
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::FCMP_OEQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::FCMP_OLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::FCMP_OLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::FCMP_OGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::FCMP_OGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::FCMP_UNE;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateFCmp(cmp_pred, converted_left->getValue(), converted_right->getValue());
}
converted_left->decvref(emitter);
converted_right->decvref(emitter);
if (succeeded) {
assert(v->getType() == g.double_ || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.double_ ? FLOAT : BOOL, v, true);
}
}
// ASSERT(left->getType() == left->getBoxType() || right->getType() == right->getBoxType(), "%s %s",
// left->getType()->debugName().c_str(), right->getType()->debugName().c_str());
ConcreteCompilerVariable* boxed_left = left->makeConverted(emitter, left->getBoxType());
ConcreteCompilerVariable* boxed_right = right->makeConverted(emitter, right->getBoxType());
llvm::Value* rtn;
bool do_patchpoint = ENABLE_ICBINEXPS && (irstate->getEffortLevel() != EffortLevel::INTERPRETED);
llvm::Value* rt_func;
void* rt_func_addr;
if (exp_type == BinOp) {
rt_func = g.funcs.binop;
rt_func_addr = (void*)binop;
} else if (exp_type == AugBinOp) {
rt_func = g.funcs.augbinop;
rt_func_addr = (void*)augbinop;
} else {
rt_func = g.funcs.compare;
rt_func_addr = (void*)compare;
}
if (do_patchpoint) {
PatchpointSetupInfo* pp = patchpoints::createBinexpPatchpoint(
emitter.currentFunction(), getOpInfoForNode(node, exc_info).getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(boxed_left->getValue());
llvm_args.push_back(boxed_right->getValue());
llvm_args.push_back(getConstantInt(type, g.i32));
llvm::Value* uncasted = emitter.createPatchpoint(pp, rt_func_addr, llvm_args, exc_info).getInstruction();
rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
} else {
rtn = emitter.createCall3(exc_info, rt_func, boxed_left->getValue(), boxed_right->getValue(),
getConstantInt(type, g.i32)).getInstruction();
}
boxed_left->decvref(emitter);
boxed_right->decvref(emitter);
if (type == AST_TYPE::In || type == AST_TYPE::NotIn || type == AST_TYPE::Is || type == AST_TYPE::IsNot) {
return unboxVar(BOXED_BOOL, rtn, true);
}
return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
return left->binexp(emitter, getOpInfoForNode(node, exc_info), right, type, exp_type);
}
CompilerVariable* evalBinOp(AST_BinOp* node, ExcInfo exc_info) {
......
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