Beispiel #1
0
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;
}
Beispiel #2
0
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);
	}
}
Beispiel #3
0
	void Shader::Compile()
	{
		GLint res;

		glCompileShader( obj );
		glGetShaderiv( obj, GL_COMPILE_STATUS, &res );

		if ( res == GL_FALSE )
			throw CompileException( GetInfoLog() );
	}
Beispiel #4
0
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;
}
Beispiel #5
0
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");
}
Beispiel #6
0
[[noreturn]] void throwErrno(const char* what) {
  throw CompileException("{}: {}", what, folly::errnoStr(errno));
}