Symbol* FunctionCall::bestMatch(Symbol *symbol, const std::vector<Type*> &actual_type, Context &context) { int minDis = 0x7fffffff; Symbol *ans = NULL; while (symbol) { int nowDis = 0; std::vector<Type*>::const_iterator it = actual_type.begin(); Function *func; if (symbol->type == Symbol::FUNCTION) func = symbol->data.function.function; else if (symbol->type == Symbol::STATIC_FUNCTION) func = symbol->data.static_function.function; else throw CompileException("Shouldn't reach here"); Function::arg_iterator it2 = func->arg_begin(); while (it != actual_type.end() && it2 != func->arg_end()) { int dis = Type::distance(*it, it2->first, context); if (dis < 0) break; nowDis += dis; it++, it2++; } if (it == actual_type.end() && it2 == func->arg_end() && nowDis < minDis) { minDis = nowDis; ans = symbol; } if (symbol->type == Symbol::FUNCTION) symbol = symbol->data.function.next; else if (symbol->type == Symbol::STATIC_FUNCTION) symbol = symbol->data.static_function.next; } return ans; }
llvm::Value* MemberAccess::getPointer(Context &context) { if (isStatic) { // find class Class *cls = targetClass->getClass(context); if (!cls) throw SymbolNotFound("No such class '" + targetClass->getName() + "'"); if (cls->getMangleName()[0] == 'J') throw InvalidType("'" + cls->getFullName() + "' is an interface"); // find symbol Symbol *symbol = cls->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("No such static member '" + identifier->getName() + "' in class '" + cls->getFullName() + "'"); if (symbol->type != Symbol::STATIC_MEMBER_VAR) throw InvalidType("'" + identifier->getName() + "' in '" + targetClass->getName() + "' is not a static member variable"); // check permission if (symbol->data.identifier.isPrivate && cls != context.currentClass) throw CompileException("'" + identifier->getName() + "' is private"); if (symbol->data.identifier.isProtected && !Class::isA(context.currentClass, cls)) throw CompileException("'" + identifier->getName() + "' is protected"); return symbol->data.identifier.value; } else { // find class if (!target->getType(context)->isObject()) throw InvalidType(std::string("Access member of a ") + target->getType(context)->getName()); Class *cls = target->getType(context)->getClass(); // find symbol Symbol *symbol = cls->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound(std::string("No such member variable in class ") + cls->getName()); if (symbol->type != Symbol::MEMBER_VAR) throw InvalidType("'" + identifier->getName() + "' in '" + targetClass->getName() + "' is not a member variable"); // check permission if (symbol->data.identifier.isPrivate && cls != context.currentClass) throw CompileException("'" + identifier->getName() + "' is private"); if (symbol->data.identifier.isProtected && !Class::isA(context.currentClass, cls)) throw CompileException("'" + identifier->getName() + "' is protected"); return addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, target->load(context), symbol->data.member.index), loc); } }
void Shader::Compile() { GLint res; glCompileShader( obj ); glGetShaderiv( obj, GL_COMPILE_STATUS, &res ); if ( res == GL_FALSE ) throw CompileException( GetInfoLog() ); }
llvm::Value* FunctionCall::load(Context &context) { std::vector<Type*> actual_type; for (std::list<Expression*>::iterator it = arg_list.begin(); it != arg_list.end(); it++) actual_type.push_back((*it)->getType(context)); Symbol *symbol = NULL; Class *targetClass = NULL; if (target == NULL) { // static call or self call if (identifier->getName().rfind("::") != std::string::npos) { // static call // find class targetClass = context.findClass(identifier->getName().substr(0, identifier->getName().rfind("::"))); if (!targetClass) throw SymbolNotFound("Class '" + identifier->getName().substr(0, identifier->getName().rfind("::")) + "'"); // find function symbol = targetClass->findSymbol(identifier->getName().substr(identifier->getName().rfind("::") + 2)); if (!symbol) throw SymbolNotFound("Function '" + identifier->getName() + "'"); // match the best override symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); // check symbol is static function if (symbol->type != Symbol::STATIC_FUNCTION) throw InvalidType("'" + symbol->data.function.function->getName() + "' is not a static function"); // check symbol's permission if (symbol->data.static_function.isPrivate && targetClass != context.currentClass) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is private"); if (symbol->data.static_function.isProtected && !Class::isA(context.currentClass, targetClass)) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is protected"); } else { // self call targetClass = context.currentClass; // find function symbol = targetClass->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("'" + identifier->getName() + "'"); symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); } } else { // member function call targetClass = target->getType(context)->getClass(); // find function symbol = targetClass->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("Function '" + identifier->getName() + "'"); symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); // check symbol is normal function if (symbol->type != Symbol::FUNCTION) throw InvalidType("function '" + symbol->data.static_function.function->getName() + "' is not a member function"); // check symbol's permission if (symbol->data.static_function.isPrivate && targetClass != context.currentClass) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is private"); if (symbol->data.static_function.isProtected && !Class::isA(context.currentClass, targetClass)) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is protected"); } llvm::Value *function; std::vector<llvm::Value*> arg_code; switch (symbol->type) { case Symbol::FUNCTION: { Expression *tmpTarget = target ? target : new Identifier("this"); if (!tmpTarget->getType(context)->isObject()) throw InvalidType(std::string("calling a function of ") + tmpTarget->getType(context)->getName()); llvm::Value *thisval = tmpTarget->load(context); if (!target) delete tmpTarget; if (targetClass->getMangleName()[0] == 'J') { // locate vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( thisval ), loc ); // for interface call, we have to recalculate the object base address // load offset from vtable llvm::Value *baseOffset = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, function, 0 ), loc ) ), loc ); // calculate the base address thisval = addDebugLoc( context, context.getBuilder().CreateIntToPtr( addDebugLoc( context, context.getBuilder().CreateSub( addDebugLoc( context, context.getBuilder().CreatePtrToInt( thisval, context.getBuilder().getInt32Ty() ), loc ), baseOffset ), loc ), context.getBuilder().getInt8PtrTy(0) ), loc ); } else { // locate vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, thisval, symbol->data.function.vtableOffset ), loc ) ), loc ); // for object call, we only need type cast thisval = context.getBuilder().CreatePointerCast( thisval, context.getBuilder().getInt8PtrTy(0) ); } // add thisval as the first argument arg_code.push_back(thisval); // load function pointer from vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, function, symbol->data.function.funcPtrOffset ), loc ) ), loc ); break; } case Symbol::STATIC_FUNCTION: function = symbol->data.static_function.function->getLLVMFunction(context); if (target) throw CompileException("Calling a static function of an object"); break; default: throw InvalidType("calling a symbol which is not a function"); } // load remaining arguments { Function *func = symbol->type == Symbol::FUNCTION ? symbol->data.function.function : symbol->data.static_function.function; Function::arg_iterator it2 = func->arg_begin(); for (std::list<Expression*>::iterator it = arg_list.begin(); it != arg_list.end(); it++, it2++) arg_code.push_back(Type::cast(context, (*it)->getType(context), (*it)->load(context), it2->first)); } // do the call llvm::Value *ans = addDebugLoc( context, context.getBuilder().CreateCall(function, llvm::ArrayRef<llvm::Value*>(arg_code)), loc); return ans; }
llvm::Value* Op2::load(Context &context) { if (op == ASSIGN) { llvm::Value *tmp = right->load(context); tmp = Type::cast(context, right->getType(context), tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); return tmp; } Type *ansType = Type::higherType(left->getType(context), right->getType(context)); llvm::Value *lhs = Type::cast(context, left->getType(context), left->load(context), ansType); llvm::Value *rhs = Type::cast(context, right->getType(context), right->load(context), ansType); // pre type check switch (op) { case ADD: case ADD_ASSIGN: case SUB: case SUB_ASSIGN: case MUL: case MUL_ASSIGN: case DIV: case DIV_ASSIGN: case PWR: case PWR_ASSIGN: case MOD: case MOD_ASSIGN: case LT: case GT: case LEQ: case GEQ: case EQ: case NEQ: if (!ansType->isNumber() && !ansType->isString()) throw InvalidType(std::string("can't apply operator ") + OpNames[op] + " to " + left->getType(context)->getName() + " and " + right->getType(context)->getName()); break; case LSH: case LSH_ASSIGN: case RSH: case RSH_ASSIGN: case BIT_OR: case BIT_OR_ASSIGN: case BIT_AND: case BIT_AND_ASSIGN: case BIT_XOR: case BIT_XOR_ASSIGN: if (!ansType->isInt()) throw InvalidType(std::string("can't apply operator ") + OpNames[op] + " to " + left->getType(context)->getName() + " and " + right->getType(context)->getName()); break; case LOG_OR: case LOG_OR_ASSIGN: case LOG_AND: case LOG_AND_ASSIGN: case LOG_XOR: case LOG_XOR_ASSIGN: if (!ansType->isBool()) throw InvalidType(std::string("can't apply operator ") + OpNames[op] + " to " + left->getType(context)->getName() + " and " + right->getType(context)->getName()); break; case ASSIGN: // this has been handled before break; } switch (op) { case ADD_ASSIGN: case ADD: { llvm::Value *tmp; if (ansType->isFloat()) tmp = addDebugLoc(context, context.getBuilder().CreateFAdd(lhs, rhs), loc); else tmp = addDebugLoc(context, context.getBuilder().CreateAdd(lhs, rhs), loc); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case SUB_ASSIGN: case SUB: { llvm::Value *tmp; if (ansType->isFloat()) tmp = addDebugLoc(context, context.getBuilder().CreateFSub(lhs, rhs), loc); else tmp = addDebugLoc(context, context.getBuilder().CreateSub(lhs, rhs), loc); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case MUL_ASSIGN: case MUL: { llvm::Value *tmp; if (ansType->isFloat()) tmp = addDebugLoc(context, context.getBuilder().CreateFMul(lhs, rhs), loc); else tmp = addDebugLoc(context, context.getBuilder().CreateMul(lhs, rhs), loc); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case DIV_ASSIGN: case DIV: { llvm::Value *tmp; if (ansType->isFloat()) tmp = addDebugLoc(context, context.getBuilder().CreateFDiv(lhs, rhs), loc); else if (ansType->isUnsigned) tmp = addDebugLoc(context, context.getBuilder().CreateUDiv(lhs, rhs), loc); else tmp = addDebugLoc(context, context.getBuilder().CreateSDiv(lhs, rhs), loc); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case MOD_ASSIGN: case MOD: { llvm::Value *tmp; if (ansType->isUnsigned) tmp = addDebugLoc(context, context.getBuilder().CreateURem(lhs, rhs), loc); else tmp = addDebugLoc(context, context.getBuilder().CreateSRem(lhs, rhs), loc); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case LSH_ASSIGN: case LSH: { llvm::Value *tmp = addDebugLoc(context, context.getBuilder().CreateShl(lhs, rhs), loc); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case RSH_ASSIGN: case RSH: { llvm::Value *tmp; if (ansType->isUnsigned) tmp = addDebugLoc(context, context.getBuilder().CreateLShr(lhs, rhs), loc); else tmp = addDebugLoc(context, context.getBuilder().CreateAShr(lhs, rhs), loc); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case LT: if (ansType->isFloat()) return addDebugLoc(context, context.getBuilder().CreateFCmpOLT(lhs, rhs), loc); else if (ansType->isInt()) { if (ansType->isUnsigned) return addDebugLoc(context, context.getBuilder().CreateICmpULT(lhs, rhs), loc); else return addDebugLoc(context, context.getBuilder().CreateICmpSLT(lhs, rhs), loc); } else if (ansType->isString()) throw NotImplemented("comparison of string"); break; case LEQ: if (ansType->isFloat()) return addDebugLoc(context, context.getBuilder().CreateFCmpOLE(lhs, rhs), loc); else if (ansType->isInt()) { if (ansType->isUnsigned) return addDebugLoc(context, context.getBuilder().CreateICmpULE(lhs, rhs), loc); else return addDebugLoc(context, context.getBuilder().CreateICmpSLE(lhs, rhs), loc); } else if (ansType->isString()) throw NotImplemented("comparison of string"); break; case GT: if (ansType->isFloat()) return addDebugLoc(context, context.getBuilder().CreateFCmpOGT(lhs, rhs), loc); else if (ansType->isInt()) { if (ansType->isUnsigned) return addDebugLoc(context, context.getBuilder().CreateICmpUGT(lhs, rhs), loc); else return addDebugLoc(context, context.getBuilder().CreateICmpSGT(lhs, rhs), loc); } else if (ansType->isString()) throw NotImplemented("comparison of string"); break; case GEQ: if (ansType->isFloat()) return addDebugLoc(context, context.getBuilder().CreateFCmpOGE(lhs, rhs), loc); else if (ansType->isInt()) { if (ansType->isUnsigned) return addDebugLoc(context, context.getBuilder().CreateICmpUGE(lhs, rhs), loc); else return addDebugLoc(context, context.getBuilder().CreateICmpSGE(lhs, rhs), loc); } else if (ansType->isString()) throw NotImplemented("comparison of string"); break; case ASSIGN: // this has been handled before break; case EQ: if (ansType->isFloat()) return addDebugLoc(context, context.getBuilder().CreateFCmpOEQ(lhs, rhs), loc); else if (ansType->isInt()) return addDebugLoc(context, context.getBuilder().CreateICmpEQ(lhs, rhs), loc); else if (ansType->isString()) throw NotImplemented("comparison of string"); break; case NEQ: if (ansType->isFloat()) return addDebugLoc(context, context.getBuilder().CreateFCmpONE(lhs, rhs), loc); else if (ansType->isInt()) return addDebugLoc(context, context.getBuilder().CreateICmpNE(lhs, rhs), loc); else if (ansType->isString()) throw NotImplemented("comparison of string"); break; case LOG_AND_ASSIGN: case BIT_AND_ASSIGN: case LOG_AND: case BIT_AND: { llvm::Value *tmp = context.getBuilder().CreateAnd(lhs, rhs); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case LOG_OR_ASSIGN: case BIT_OR_ASSIGN: case LOG_OR: case BIT_OR: { llvm::Value *tmp = context.getBuilder().CreateOr(lhs, rhs); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case LOG_XOR_ASSIGN: case BIT_XOR_ASSIGN: case LOG_XOR: case BIT_XOR: { llvm::Value *tmp = context.getBuilder().CreateXor(lhs, rhs); if (hasAssign(op)) { tmp = Type::cast(context, ansType, tmp, left->getType(context)); addDebugLoc( context, left->store(context, tmp), loc); } return tmp; } case PWR: case PWR_ASSIGN: throw NotImplemented(std::string("operator '") + OpNames[op] + "'"); } throw CompileException("Shouldn't reach here"); }
[[noreturn]] void throwErrno(const char* what) { throw CompileException("{}: {}", what, folly::errnoStr(errno)); }