<commit_before>/** distributed_moses.cc ---
 *
 * Copyright (C) 2011 OpenCog Foundation
 *
 * Author: Nil Geisweiller
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "distributed_moses.h"

namespace opencog { namespace moses {

using namespace boost::program_options;
using boost::tuple;
using boost::make_tuple;
using boost::lexical_cast;

pid_t get_parent_pid() {
    return getpid();
}

int get_pid(const proc_map::value_type& pmv) {
    return pmv.first;
}
string get_cmd(const proc_map::value_type& pmv) {
    return pmv.second.get<0>();
}
string get_tmp(const proc_map::value_type& pmv) {
    return pmv.second.get<1>();
}
FILE* get_file(const proc_map::value_type& pmv) {
    return pmv.second.get<2>();
}
unsigned get_num_jobs(const proc_map::value_type& pmv) {
    return pmv.second.get<3>();
}

const string& get_hostname(const host_proc_map::value_type& hp) {
    return hp.first;
}
const proc_map& get_proc_map(const host_proc_map::value_type& hp) {
    return hp.second;
}
const unsigned get_total_jobs(const host_proc_map::value_type& hp) {
    // return the number of jobs for all processes of hp's host
    unsigned acc = 0;
    foreach(const proc_map::value_type& p, get_proc_map(hp))
        acc += get_num_jobs(p);
    return acc;
}

unsigned running_proc_count(const host_proc_map& hpm) {
    unsigned acc = 0;
    foreach(const host_proc_map::value_type& hpmv, hpm)
        acc += hpmv.second.size();
    return acc;
}

string build_cmdline(const variables_map& vm,
                     const combo_tree& tr,
                     const string& host_name,
                     unsigned n_jobs,
                     unsigned max_evals,
                     unsigned gen_idx) {
    string res;
    if(host_name == localhost)
        res = "moses";
    else
        res = string("ssh ") + host_name + " 'moses";
    // replicate initial command's options, except all of those
    // interfering with the command to be built, that is:
    // exemplar, output options, jobs, max_evals, max_gens and
    // log file name options.
    for(variables_map::const_iterator it = vm.begin(); it != vm.end(); ++it) {
        if(it->first != exemplars_str_opt.first
           && it->first != exemplars_str_opt.first
           && it->first != output_score_opt.first
           && it->first != output_bscore_opt.first
           && it->first != output_complexity_opt.first
           && it->first != output_eval_number_opt.first
           && it->first != output_with_labels_opt.first
           && it->first != output_file_opt.first
           && it->first != jobs_opt.first
           && it->first != max_evals_opt.first
           && it->first != max_gens_opt.first
           && it->first != result_count_opt.first
           && it->first != log_file_opt.first
           && it->first != log_file_dep_opt_opt.first
           && !it->second.defaulted()) {
            string opt_name(" --");
            opt_name += it->first + " \"";
            res += opt_name + to_string(it->second, string("\"") + opt_name) + "\"";
        }
    }
    // add exemplar option
    stringstream ss;
    ss << tr;

    // When using ssh, must escape the $varname
    string trs = ss.str();
    size_t pos = trs.find('$');
    while (pos != string::npos) {
        trs.insert(pos, 1, '\\');
        pos = trs.find('$', pos+2);
    }
    res += string(" -") + exemplars_str_opt.second + " \"" + trs + "\"";
    // add output options
    res += string(" -") + output_bscore_opt.second + " 1";
    res += string(" -") + output_complexity_opt.second + " 1";
    res += string(" -") + output_eval_number_opt.second + " 1";
    // add number of jobs option
    res += string(" -") + jobs_opt.second + lexical_cast<string>(n_jobs);
    // add number of evals option
    res += string(" -") + max_evals_opt.second + " "
        + lexical_cast<string>(max_evals);
    // add one generation option
    res += string(" -") + max_gens_opt.second + " 1";
    // add log option determined name option
    res += string(" -") + log_file_opt.second + "distributed_moses"
        + "_from_parent_" + lexical_cast<string>(get_parent_pid())
        + "_gen_" + lexical_cast<string>(gen_idx) + ".log";
    // add option to return all results
    res += string(" -") + result_count_opt.second + " -1";

    if(host_name != localhost) {
        res += "'";
    }

    return res;
}

proc_map::value_type launch_cmd(string cmd, unsigned n_jobs) {
    // append " > tempfile&" to cmd
    char tempfile[] = "/tmp/mosesXXXXXX";
    int fd = mkstemp(tempfile);
    if(fd == -1) {
        std::cerr << "could not create temporary file" << std::endl;
        exit(1);
    }
    string tmp(tempfile);
    cmd += string(" > ") + tmp + "&";

    // launch the command
    int res = system(cmd.c_str());
    if(res != 0) {
        std::cerr << "the execution of " << cmd << "has failed" << std::endl;
        exit(1);
    }
    FILE* fp = fopen(tempfile, "r");

    // get its PID
    string exec_name = cmd.substr(0, cmd.find(" "));
    FILE* fp_pid = popen(string("pgrep -n ").append(exec_name).c_str(), "r");
    int pid;
    int count_matches = fscanf(fp_pid, "%u", &pid);
    OC_ASSERT(count_matches == 1);

    // make the proc_map
    return make_pair(pid, boost::make_tuple(cmd, tmp, fp, n_jobs));
}

bool is_being_written(const string& file_name, int pid)
{
    // Arghhh FIXME. fuser might not be installed, or it may not be in
    // the default search path.  RedHat/CentOS puts it into /sbin/fuser
    // which is not in the default searchpath.
    FILE* fp = popen(string("fuser ").append(file_name).append(" 2> /dev/null").c_str(), "r");
    while (!feof(fp)) {
        int p;
        int count_matches = fscanf(fp, "%u", &p);
        OC_ASSERT(count_matches == 1, "The fuser command failed; is it installed?");
        if (pid == p)
            return true;
    }
    return false;
}

bool is_running(const proc_map::value_type& pmv)
{
    // check if the file is still empty
    FILE* fp = get_file(pmv);
    if (fseek(fp, 0, SEEK_END)) {
        std::cerr << "Error while seeking to end of file" << std::endl;
        exit(1);
    }
    int length = ftell(fp);
    if (length < 0) {
        std::cerr << "Error while reading file position" << std::endl;
        exit(1);
    } else if (length == 0) {
        return true;
    }
    return is_being_written(get_tmp(pmv), get_pid(pmv));
}

void parse_result(istream& in, metapop_candidates& candidates, int& evals)
{
    in.seekg(0);
    while (!in.eof()) {
        string s;
        in >> s;
        if (s.empty())
            continue;
        else if (s == string(number_of_evals_str).append(":")) {
            in >> evals;
        } else {
            // read score
            score_t score = lexical_cast<score_t>(s);
            // read complexity
            complexity_t complexity;
            in >> complexity;
            // read complexity penalty
            score_t complexity_penalty;
            in >> complexity_penalty;
            // read complexity penalty
            score_t diversity_penalty;
            in >> diversity_penalty;
            // read candidate
            combo_tree tr;
            in >> tr;
            // read bscore, which is preceeded by the bscore penalty
            score_t bpenalty;
            in >> bpenalty;
            OC_ASSERT(bpenalty == complexity_penalty);

            penalized_behavioral_score pbs;
            behavioral_score &bscore = pbs.first;
            istreamContainer(in, std::back_inserter(bscore), "[", "]");
            pbs.second = bpenalty;
            // insert read element in candidates
            bscored_combo_tree candidate =
                make_pair(tr, make_pair(pbs, composite_score(score, complexity, complexity_penalty)));
            candidates.insert(candidate);
            // Logger
            if (logger().isFineEnabled()) {
                logger().fine("Parsed candidate:");
                stringstream ss;
                logger().fine(ostream_bscored_combo_tree(ss, candidate,
                                                         true, true).str());
            }
            // ~Logger
        }
    }
};

void parse_result(const proc_map::value_type& pmv,
                  metapop_candidates& candidates, int& evals)
{
    FILE* fp = get_file(pmv);
    // build istream from fp
    __gnu_cxx::stdio_filebuf<char> pipe_buf(fp, ios_base::in);
    istream sp(&pipe_buf);
    // parse result
    parse_result(sp, candidates, evals);
    // close fp
    pclose(fp);
}

host_proc_map init(const jobs_t& jobs)
{
    host_proc_map hpm;
    foreach(const jobs_t::value_type job, jobs) {
        hpm.insert(make_pair(job.first, proc_map()));
    }
    return hpm;
}

proc_map::iterator remove_proc(proc_map& pm,  proc_map::iterator it)
{
    proc_map::iterator next_it(it);
    next_it++;
    pm.erase(it);
    return next_it;
}

void killall(proc_map& pm)
{
    for(proc_map::iterator it = pm.begin(); it != pm.end();) {
        if(is_running(*it))
            kill(get_pid(*it), 15); // send a TERM signal
        it = remove_proc(pm, it);
    }
}

void killall(host_proc_map& hpm)
{
    foreach(host_proc_map::value_type& hpmv, hpm)
        killall(hpmv.second);
}

host_proc_map::iterator find_free_resource(host_proc_map& hpm,
                                           const jobs_t& jobs)
{
    host_proc_map::iterator hpm_it = hpm.begin();
    for(jobs_t::const_iterator jit = jobs.begin(); jit != jobs.end();
        ++jit, ++hpm_it) {
        OC_ASSERT(jit->first == hpm_it->first,
                  "Hosts names are different, there must be a bug");
        if(get_total_jobs(*hpm_it) < jit->second)
            break;
    }
    return hpm_it;
}

bool all_resources_free(const host_proc_map& hpm)
{
    foreach(const host_proc_map::value_type& hpmv, hpm) {
        if(!hpmv.second.empty())
            return false;
    }
    return true;
}

} // ~namespace moses
} // ~namespace opencog
<commit_msg>moses: plug resource leak leading to crash in dist moses.<commit_after>/** distributed_moses.cc ---
 *
 * Copyright (C) 2011 OpenCog Foundation
 *
 * Author: Nil Geisweiller
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "distributed_moses.h"

namespace opencog { namespace moses {

using namespace boost::program_options;
using boost::tuple;
using boost::make_tuple;
using boost::lexical_cast;

pid_t get_parent_pid() {
    return getpid();
}

int get_pid(const proc_map::value_type& pmv) {
    return pmv.first;
}
string get_cmd(const proc_map::value_type& pmv) {
    return pmv.second.get<0>();
}
string get_tmp(const proc_map::value_type& pmv) {
    return pmv.second.get<1>();
}
FILE* get_file(const proc_map::value_type& pmv) {
    return pmv.second.get<2>();
}
unsigned get_num_jobs(const proc_map::value_type& pmv) {
    return pmv.second.get<3>();
}

const string& get_hostname(const host_proc_map::value_type& hp) {
    return hp.first;
}
const proc_map& get_proc_map(const host_proc_map::value_type& hp) {
    return hp.second;
}
const unsigned get_total_jobs(const host_proc_map::value_type& hp) {
    // return the number of jobs for all processes of hp's host
    unsigned acc = 0;
    foreach(const proc_map::value_type& p, get_proc_map(hp))
        acc += get_num_jobs(p);
    return acc;
}

unsigned running_proc_count(const host_proc_map& hpm) {
    unsigned acc = 0;
    foreach(const host_proc_map::value_type& hpmv, hpm)
        acc += hpmv.second.size();
    return acc;
}

string build_cmdline(const variables_map& vm,
                     const combo_tree& tr,
                     const string& host_name,
                     unsigned n_jobs,
                     unsigned max_evals,
                     unsigned gen_idx) {
    string res;
    if(host_name == localhost)
        res = "moses";
    else
        res = string("ssh ") + host_name + " 'moses";
    // replicate initial command's options, except all of those
    // interfering with the command to be built, that is:
    // exemplar, output options, jobs, max_evals, max_gens and
    // log file name options.
    for(variables_map::const_iterator it = vm.begin(); it != vm.end(); ++it) {
        if(it->first != exemplars_str_opt.first
           && it->first != exemplars_str_opt.first
           && it->first != output_score_opt.first
           && it->first != output_bscore_opt.first
           && it->first != output_complexity_opt.first
           && it->first != output_eval_number_opt.first
           && it->first != output_with_labels_opt.first
           && it->first != output_file_opt.first
           && it->first != jobs_opt.first
           && it->first != max_evals_opt.first
           && it->first != max_gens_opt.first
           && it->first != result_count_opt.first
           && it->first != log_file_opt.first
           && it->first != log_file_dep_opt_opt.first
           && !it->second.defaulted()) {
            string opt_name(" --");
            opt_name += it->first + " \"";
            res += opt_name + to_string(it->second, string("\"") + opt_name) + "\"";
        }
    }
    // add exemplar option
    stringstream ss;
    ss << tr;

    // When using ssh, must escape the $varname
    string trs = ss.str();
    size_t pos = trs.find('$');
    while (pos != string::npos) {
        trs.insert(pos, 1, '\\');
        pos = trs.find('$', pos+2);
    }
    res += string(" -") + exemplars_str_opt.second + " \"" + trs + "\"";
    // add output options
    res += string(" -") + output_bscore_opt.second + " 1";
    res += string(" -") + output_complexity_opt.second + " 1";
    res += string(" -") + output_eval_number_opt.second + " 1";
    // add number of jobs option
    res += string(" -") + jobs_opt.second + lexical_cast<string>(n_jobs);
    // add number of evals option
    res += string(" -") + max_evals_opt.second + " "
        + lexical_cast<string>(max_evals);
    // add one generation option
    res += string(" -") + max_gens_opt.second + " 1";
    // add log option determined name option
    res += string(" -") + log_file_opt.second + "distributed_moses"
        + "_from_parent_" + lexical_cast<string>(get_parent_pid())
        + "_gen_" + lexical_cast<string>(gen_idx) + ".log";
    // add option to return all results
    res += string(" -") + result_count_opt.second + " -1";

    if(host_name != localhost) {
        res += "'";
    }

    return res;
}

proc_map::value_type launch_cmd(string cmd, unsigned n_jobs) {
    // append " > tempfile&" to cmd
    char tempfile[] = "/tmp/mosesXXXXXX";
    int fd = mkstemp(tempfile);
    if(fd == -1) {
        std::cerr << "could not create temporary file" << std::endl;
        exit(1);
    }
    string tmp(tempfile);
    cmd += string(" > ") + tmp + "&";

    // launch the command
    int res = system(cmd.c_str());
    if(res != 0) {
        std::cerr << "the execution of " << cmd << "has failed" << std::endl;
        exit(1);
    }
    FILE* fp = fopen(tempfile, "r");

    // get its PID
    string exec_name = cmd.substr(0, cmd.find(" "));
    FILE* fp_pid = popen(string("pgrep -n ").append(exec_name).c_str(), "r");
    int pid;
    int count_matches = fscanf(fp_pid, "%u", &pid);
    OC_ASSERT(count_matches == 1);
    pclose(fp_pid);

    // make the proc_map
    return make_pair(pid, boost::make_tuple(cmd, tmp, fp, n_jobs));
}

bool is_being_written(const string& file_name, int pid)
{
    // Arghhh FIXME. fuser might not be installed, or it may not be in
    // the default search path.  RedHat/CentOS puts it into /sbin/fuser
    // which is not in the default searchpath.
    FILE* fp = popen(string("fuser ").append(file_name).append(" 2> /dev/null").c_str(), "r");
    while (!feof(fp)) {
        int p;
        int count_matches = fscanf(fp, "%u", &p);
        OC_ASSERT(count_matches == 1, "The fuser command failed; is it installed?");
        if (pid == p) {
            pclose(fp);
            return true;
        }
    }
    pclose(fp);
    return false;
}

bool is_running(const proc_map::value_type& pmv)
{
    // check if the file is still empty
    FILE* fp = get_file(pmv);
    if (fseek(fp, 0, SEEK_END)) {
        std::cerr << "Error while seeking to end of file" << std::endl;
        exit(1);
    }
    int length = ftell(fp);
    if (length < 0) {
        std::cerr << "Error while reading file position" << std::endl;
        exit(1);
    } else if (length == 0) {
        return true;
    }
    return is_being_written(get_tmp(pmv), get_pid(pmv));
}

void parse_result(istream& in, metapop_candidates& candidates, int& evals)
{
    in.seekg(0);
    while (!in.eof()) {
        string s;
        in >> s;
        if (s.empty())
            continue;
        else if (s == string(number_of_evals_str).append(":")) {
            in >> evals;
        } else {
            // read score
            score_t score = lexical_cast<score_t>(s);
            // read complexity
            complexity_t complexity;
            in >> complexity;
            // read complexity penalty
            score_t complexity_penalty;
            in >> complexity_penalty;
            // read complexity penalty
            score_t diversity_penalty;
            in >> diversity_penalty;
            // read candidate
            combo_tree tr;
            in >> tr;
            // read bscore, which is preceeded by the bscore penalty
            score_t bpenalty;
            in >> bpenalty;
            OC_ASSERT(bpenalty == complexity_penalty);

            penalized_behavioral_score pbs;
            behavioral_score &bscore = pbs.first;
            istreamContainer(in, std::back_inserter(bscore), "[", "]");
            pbs.second = bpenalty;
            // insert read element in candidates
            bscored_combo_tree candidate =
                make_pair(tr, make_pair(pbs, composite_score(score, complexity, complexity_penalty)));
            candidates.insert(candidate);
            // Logger
            if (logger().isFineEnabled()) {
                logger().fine("Parsed candidate:");
                stringstream ss;
                logger().fine(ostream_bscored_combo_tree(ss, candidate,
                                                         true, true).str());
            }
            // ~Logger
        }
    }
};

void parse_result(const proc_map::value_type& pmv,
                  metapop_candidates& candidates, int& evals)
{
    FILE* fp = get_file(pmv);
    // build istream from fp
    __gnu_cxx::stdio_filebuf<char> pipe_buf(fp, ios_base::in);
    istream sp(&pipe_buf);
    // parse result
    parse_result(sp, candidates, evals);
    // close fp
    fclose(fp);
}

host_proc_map init(const jobs_t& jobs)
{
    host_proc_map hpm;
    foreach(const jobs_t::value_type job, jobs) {
        hpm.insert(make_pair(job.first, proc_map()));
    }
    return hpm;
}

proc_map::iterator remove_proc(proc_map& pm,  proc_map::iterator it)
{
    proc_map::iterator next_it(it);
    next_it++;
    pm.erase(it);
    return next_it;
}

void killall(proc_map& pm)
{
    for(proc_map::iterator it = pm.begin(); it != pm.end();) {
        if(is_running(*it))
            kill(get_pid(*it), 15); // send a TERM signal
        it = remove_proc(pm, it);
    }
}

void killall(host_proc_map& hpm)
{
    foreach(host_proc_map::value_type& hpmv, hpm)
        killall(hpmv.second);
}

host_proc_map::iterator find_free_resource(host_proc_map& hpm,
                                           const jobs_t& jobs)
{
    host_proc_map::iterator hpm_it = hpm.begin();
    for(jobs_t::const_iterator jit = jobs.begin(); jit != jobs.end();
        ++jit, ++hpm_it) {
        OC_ASSERT(jit->first == hpm_it->first,
                  "Hosts names are different, there must be a bug");
        if(get_total_jobs(*hpm_it) < jit->second)
            break;
    }
    return hpm_it;
}

bool all_resources_free(const host_proc_map& hpm)
{
    foreach(const host_proc_map::value_type& hpmv, hpm) {
        if(!hpmv.second.empty())
            return false;
    }
    return true;
}

} // ~namespace moses
} // ~namespace opencog
<|endoftext|>


<commit_before><commit_msg>Implement support for simple nested function usage<commit_after><|endoftext|>


<commit_before><commit_msg>coverity#1266509 Useless call<commit_after><|endoftext|>


<commit_before>#include "apps_starter.h"
#include "../lang/lang.h"
#include "../configurator/configurator.h"
#include "../windlg/windlg.h"
#include "../libscreen/libscreen.h"
#include <wait.h>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include <curses.h>

using namespace std;

int stat;

/*int app_start(int number_of_app, const char* parametrs) {
	string full_path = configurator(APPS_FILE, str(number_of_app) + "_app_path", "", false) + "/" + configurator(APPS_FILE, str(number_of_app) + "_app_launcher", "", false);
	erase();
	pid_t pid = fork();
	if (pid == 0)
		execl(full_path.c_str(), parametrs, NULL); // parent process
	else {
		erase();
		wait(&stat);
		refresh();
		// getch();

		// timeout(-1);
		// string test_output;
		// DLGSTR teststr = {}; // Только так!!!
		// teststr.title = "Pre pre pre ... Alpha";
		// teststr.style = 1;
		// teststr.line = "Dear user, it's not full version of OS!/nThis is just an example of how might look this OS.";
		// msg_win(teststr);
		// update_screen();
	}
	// TEST
	return 0;
}*/

int app_start(int number_of_app, const char* parametrs) {
	string full_path = configurator(APPS_FILE, str(number_of_app) + "_app_path", "", false) + "/" + configurator(APPS_FILE, str(number_of_app) + "_app_launcher", "", false);
	erase();
	endwin();

	int		status;
	pid_t	chpid = fork();

	if (chpid == 0) {
		execl(full_path.c_str(), parametrs, NULL); // parent process
	} else {
		waitpid(chpid,&status,WUNTRACED);
		initscr();
		start_color();
		keypad (stdscr, true);
		noecho();
		curs_set(0);
		erase();
	}
	return 0;
}<commit_msg>Little fixes<commit_after>#include "../lang/lang.h"
#include "../configurator/configurator.h"
#include "../windlg/windlg.h"
#include "../libscreen/libscreen.h"
#include "apps_starter.h"

int app_start(int number_of_app, const char* parametrs) {
	std::string full_path = configurator(APPS_FILE, str(number_of_app) + "_app_path", "", false) + "/" + configurator(APPS_FILE, str(number_of_app) + "_app_launcher", "", false);

	erase();
	endwin();

	int		status;
	pid_t	chpid	= fork();

	if (chpid == 0) {
		if (execl(full_path.c_str(), parametrs, NULL) == -1) // parent process
			exit(0);
	} else {
		waitpid(chpid,&status,WUNTRACED);
		init_display();
	}
	return 0;
}<|endoftext|>


<commit_before>/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/formatter.h"
#include "kernel/context.h"

namespace lean {
/**
   \brief Very basic printer for expressions.
   It is mainly used when debugging code.
*/
struct print_expr_fn {
    std::ostream & m_out;

    std::ostream & out() { return m_out; }

    bool is_atomic(expr const & a) {
        return ::lean::is_atomic(a) || is_mlocal(a);
    }

    void print_child(expr const & a, context const & c) {
        if (is_atomic(a)) {
            print(a, c);
        } else {
            out() << "("; print(a, c); out() << ")";
        }
    }

    void print_macro(expr const & a, context const & c) {
        macro_def(a).display(out());
        for (unsigned i = 0; i < macro_num_args(a); i++) {
            out() << " "; print_child(macro_arg(a, i), c);
        }
    }

    void print_sort(expr const & a) {
        if (is_zero(sort_level(a))) {
            out() << "Bool";
        } else if (is_one(sort_level(a))) {
            out() << "Type";
        } else {
            out() << "Type.{" << sort_level(a) << "}";
        }
    }

    void print_app(expr const & e, context const & c) {
        expr const & f = app_fn(e);
        if (is_app(f))
            print(f, c);
        else
            print_child(f, c);
        out() << " ";
        print_child(app_arg(e), c);
    }

    void print_arrow_body(expr const & a, context const & c) {
        if (is_atomic(a) || is_arrow(a))
            return print(a, c);
        else
            return print_child(a, c);
    }

    void print_binder(char const * bname, expr const & e, context const & c) {
        out() << bname << " ";
        if (binding_info(e).is_implicit())
            out() << "{";
        else if (binding_info(e).is_cast())
            out() << "[";
        out() << binding_name(e) << " : ";
        print_child(binding_domain(e), c);
        if (binding_info(e).is_implicit())
            out() << "}";
        else if (binding_info(e).is_cast())
            out() << "]";
        out() << ", ";
        print_child(binding_body(e), extend(c, binding_name(e), binding_domain(e)));
    }

    void print_const(expr const & a) {
        list<level> const & ls = const_levels(a);
        out() << const_name(a);
        if (!is_nil(ls)) {
            out() << ".{";
            bool first = true;
            for (auto l : ls) {
                if (first) first = false; else out() << " ";
                out() << l;
            }
            out() << "}";
        }
    }

    void print(expr const & a, context const & c) {
        switch (a.kind()) {
        case expr_kind::Meta:
            out() << "?" << mlocal_name(a);
            break;
        case expr_kind::Local:
            out() << local_pp_name(a);
            break;
        case expr_kind::Var: {
            auto e = find(c, var_idx(a));
            if (e)
                out() << e->get_name() << "#" << var_idx(a);
            else
                out() << "#" << var_idx(a);
            break;
        }
        case expr_kind::Constant:
            print_const(a);
            break;
        case expr_kind::App:
            print_app(a, c);
            break;
        case expr_kind::Lambda:
            print_binder("fun", a, c);
            break;
        case expr_kind::Pi:
            if (!is_arrow(a)) {
                print_binder("Pi", a, c);
            } else {
                print_child(binding_domain(a), c);
                out() << " -> ";
                print_arrow_body(binding_body(a), extend(c, binding_binder(a)));
            }
            break;
        case expr_kind::Let:
            out() << "let " << let_name(a);
            out() << " : ";
            print(let_type(a), c);
            out() << " := ";
            print(let_value(a), c);
            out() << " in ";
            print_child(let_body(a), extend(c, let_name(a), let_value(a)));
            break;
        case expr_kind::Sort:
            print_sort(a);
            break;
        case expr_kind::Macro:
            print_macro(a, c);
            break;
        }
    }

    print_expr_fn(std::ostream & out):m_out(out) {}

    void operator()(expr const & e, context const & c) {
        print(e, c);
    }
};

std::ostream & operator<<(std::ostream & out, expr const & e) {
    print_expr_fn pr(out);
    pr(e, context());
    return out;
}

class simple_formatter_cell : public formatter_cell {
public:
    virtual format operator()(environment const &, expr const & e, options const &) {
        std::ostringstream s; s << e; return format(s.str());
    }
};
formatter mk_simple_formatter() {
    return mk_formatter(simple_formatter_cell());
}
void print(lean::expr const & a) { std::cout << a << std::endl; }
}
<commit_msg>feat(kernel/formatter): make simple_formatter display Type instead of Bool if impredicativity is disabled<commit_after>/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/formatter.h"
#include "kernel/context.h"
#include "kernel/environment.h"

namespace lean {
/**
   \brief Very basic printer for expressions.
   It is mainly used when debugging code.
*/
struct print_expr_fn {
    std::ostream & m_out;
    bool m_type0_as_bool;

    std::ostream & out() { return m_out; }

    bool is_atomic(expr const & a) {
        return ::lean::is_atomic(a) || is_mlocal(a);
    }

    void print_child(expr const & a, context const & c) {
        if (is_atomic(a)) {
            print(a, c);
        } else {
            out() << "("; print(a, c); out() << ")";
        }
    }

    void print_macro(expr const & a, context const & c) {
        macro_def(a).display(out());
        for (unsigned i = 0; i < macro_num_args(a); i++) {
            out() << " "; print_child(macro_arg(a, i), c);
        }
    }

    void print_sort(expr const & a) {
        if (is_zero(sort_level(a))) {
            if (m_type0_as_bool)
                out() << "Bool";
            else
                out() << "Type";
        } else if (m_type0_as_bool && is_one(sort_level(a))) {
            out() << "Type";
        } else {
            out() << "Type.{" << sort_level(a) << "}";
        }
    }

    void print_app(expr const & e, context const & c) {
        expr const & f = app_fn(e);
        if (is_app(f))
            print(f, c);
        else
            print_child(f, c);
        out() << " ";
        print_child(app_arg(e), c);
    }

    void print_arrow_body(expr const & a, context const & c) {
        if (is_atomic(a) || is_arrow(a))
            return print(a, c);
        else
            return print_child(a, c);
    }

    void print_binder(char const * bname, expr const & e, context const & c) {
        out() << bname << " ";
        if (binding_info(e).is_implicit())
            out() << "{";
        else if (binding_info(e).is_cast())
            out() << "[";
        out() << binding_name(e) << " : ";
        print_child(binding_domain(e), c);
        if (binding_info(e).is_implicit())
            out() << "}";
        else if (binding_info(e).is_cast())
            out() << "]";
        out() << ", ";
        print_child(binding_body(e), extend(c, binding_name(e), binding_domain(e)));
    }

    void print_const(expr const & a) {
        list<level> const & ls = const_levels(a);
        out() << const_name(a);
        if (!is_nil(ls)) {
            out() << ".{";
            bool first = true;
            for (auto l : ls) {
                if (first) first = false; else out() << " ";
                out() << l;
            }
            out() << "}";
        }
    }

    void print(expr const & a, context const & c) {
        switch (a.kind()) {
        case expr_kind::Meta:
            out() << "?" << mlocal_name(a);
            break;
        case expr_kind::Local:
            out() << local_pp_name(a);
            break;
        case expr_kind::Var: {
            auto e = find(c, var_idx(a));
            if (e)
                out() << e->get_name() << "#" << var_idx(a);
            else
                out() << "#" << var_idx(a);
            break;
        }
        case expr_kind::Constant:
            print_const(a);
            break;
        case expr_kind::App:
            print_app(a, c);
            break;
        case expr_kind::Lambda:
            print_binder("fun", a, c);
            break;
        case expr_kind::Pi:
            if (!is_arrow(a)) {
                print_binder("Pi", a, c);
            } else {
                print_child(binding_domain(a), c);
                out() << " -> ";
                print_arrow_body(binding_body(a), extend(c, binding_binder(a)));
            }
            break;
        case expr_kind::Let:
            out() << "let " << let_name(a);
            out() << " : ";
            print(let_type(a), c);
            out() << " := ";
            print(let_value(a), c);
            out() << " in ";
            print_child(let_body(a), extend(c, let_name(a), let_value(a)));
            break;
        case expr_kind::Sort:
            print_sort(a);
            break;
        case expr_kind::Macro:
            print_macro(a, c);
            break;
        }
    }

    print_expr_fn(std::ostream & out, bool type0_as_bool = true):m_out(out), m_type0_as_bool(type0_as_bool) {}

    void operator()(expr const & e, context const & c) {
        print(e, c);
    }
};

std::ostream & operator<<(std::ostream & out, expr const & e) {
    print_expr_fn pr(out);
    pr(e, context());
    return out;
}

class simple_formatter_cell : public formatter_cell {
public:
    virtual format operator()(environment const & env, expr const & e, options const &) {
        std::ostringstream s;
        print_expr_fn pr(s, env.prop_proof_irrel());
        pr(e, context());
        return format(s.str());
    }
};
formatter mk_simple_formatter() {
    return mk_formatter(simple_formatter_cell());
}
void print(lean::expr const & a) { std::cout << a << std::endl; }
}
<|endoftext|>


<commit_before><commit_msg>fix atlas allocator<commit_after><|endoftext|>


<commit_before>//===--- TargetInfo.cpp - Information about Target machine ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the TargetInfo and TargetInfoImpl interfaces.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdlib>
using namespace clang;

// TargetInfo Constructor.
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
  // Set defaults.  Defaults are set for a 32-bit RISC platform,
  // like PPC or SPARC.
  // These should be overridden by concrete targets as needed.
  CharIsSigned = true;
  TLSSupported = true;
  PointerWidth = PointerAlign = 32;
  WCharWidth = WCharAlign = 32;
  IntWidth = IntAlign = 32;
  LongWidth = LongAlign = 32;
  LongLongWidth = LongLongAlign = 64;
  FloatWidth = 32;
  FloatAlign = 32;
  DoubleWidth = 64;
  DoubleAlign = 64;
  LongDoubleWidth = 64;
  LongDoubleAlign = 64;
  IntMaxTWidth = 64;
  SizeType = UnsignedLong;
  PtrDiffType = SignedLong;
  IntMaxType = SignedLongLong;
  UIntMaxType = UnsignedLongLong;
  IntPtrType = SignedLong;
  WCharType = SignedInt;
  FloatFormat = &llvm::APFloat::IEEEsingle;
  DoubleFormat = &llvm::APFloat::IEEEdouble;
  LongDoubleFormat = &llvm::APFloat::IEEEdouble;
  DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
                      "i64:64:64-f32:32:32-f64:64:64";
  UserLabelPrefix = "_";
}

// Out of line virtual dtor for TargetInfo.
TargetInfo::~TargetInfo() {}

/// getTypeName - Return the user string for the specified integer type enum.
/// For example, SignedShort -> "short".
const char *TargetInfo::getTypeName(IntType T) {
  switch (T) {
  default: assert(0 && "not an integer!");
  case SignedShort:      return "short";
  case UnsignedShort:    return "unsigned short";
  case SignedInt:        return "int";
  case UnsignedInt:      return "unsigned int";
  case SignedLong:       return "long int";
  case UnsignedLong:     return "long unsigned int";
  case SignedLongLong:   return "long long int";
  case UnsignedLongLong: return "long long unsigned int";
  }
}

//===----------------------------------------------------------------------===//

static void removeGCCRegisterPrefix(const char *&Name) {
  if (Name[0] == '%' || Name[0] == '#')
    Name++;
}

/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
  const char * const *Names;
  unsigned NumNames;

  // Get rid of any register prefix.
  removeGCCRegisterPrefix(Name);

  if (strcmp(Name, "memory") == 0 ||
      strcmp(Name, "cc") == 0)
    return true;

  getGCCRegNames(Names, NumNames);

  // If we have a number it maps to an entry in the register name array.
  if (isdigit(Name[0])) {
    char *End;
    int n = (int)strtol(Name, &End, 0);
    if (*End == 0)
      return n >= 0 && (unsigned)n < NumNames;
  }

  // Check register names.
  for (unsigned i = 0; i < NumNames; i++) {
    if (strcmp(Name, Names[i]) == 0)
      return true;
  }

  // Now check aliases.
  const GCCRegAlias *Aliases;
  unsigned NumAliases;

  getGCCRegAliases(Aliases, NumAliases);
  for (unsigned i = 0; i < NumAliases; i++) {
    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
      if (!Aliases[i].Aliases[j])
        break;
      if (strcmp(Aliases[i].Aliases[j], Name) == 0)
        return true;
    }
  }

  return false;
}

const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
  assert(isValidGCCRegisterName(Name) && "Invalid register passed in");

  removeGCCRegisterPrefix(Name);

  const char * const *Names;
  unsigned NumNames;

  getGCCRegNames(Names, NumNames);

  // First, check if we have a number.
  if (isdigit(Name[0])) {
    char *End;
    int n = (int)strtol(Name, &End, 0);
    if (*End == 0) {
      assert(n >= 0 && (unsigned)n < NumNames &&
             "Out of bounds register number!");
      return Names[n];
    }
  }

  // Now check aliases.
  const GCCRegAlias *Aliases;
  unsigned NumAliases;

  getGCCRegAliases(Aliases, NumAliases);
  for (unsigned i = 0; i < NumAliases; i++) {
    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
      if (!Aliases[i].Aliases[j])
        break;
      if (strcmp(Aliases[i].Aliases[j], Name) == 0)
        return Aliases[i].Register;
    }
  }

  return Name;
}

bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
  const char *Name = Info.getConstraintStr().c_str();
  // An output constraint must start with '=' or '+'
  if (*Name != '=' && *Name != '+')
    return false;

  if (*Name == '+')
    Info.setIsReadWrite();

  Name++;
  while (*Name) {
    switch (*Name) {
    default:
      if (!validateAsmConstraint(Name, Info)) {
        // FIXME: We temporarily return false
        // so we can add more constraints as we hit it.
        // Eventually, an unknown constraint should just be treated as 'g'.
        return false;
      }
    case '&': // early clobber.
      break;
    case 'r': // general register.
      Info.setAllowsRegister();
      break;
    case 'm': // memory operand.
      Info.setAllowsMemory();
      break;
    case 'g': // general register, memory operand or immediate integer.
    case 'X': // any operand.
      Info.setAllowsRegister();
      Info.setAllowsMemory();
      break;
    }

    Name++;
  }

  return true;
}

bool TargetInfo::resolveSymbolicName(const char *&Name,
                                     ConstraintInfo *OutputConstraints,
                                     unsigned NumOutputs,
                                     unsigned &Index) const {
  assert(*Name == '[' && "Symbolic name did not start with '['");
  Name++;
  const char *Start = Name;
  while (*Name && *Name != ']')
    Name++;

  if (!*Name) {
    // Missing ']'
    return false;
  }

  std::string SymbolicName(Start, Name - Start);

  for (Index = 0; Index != NumOutputs; ++Index)
    if (SymbolicName == OutputConstraints[Index].getName())
      return true;

  return false;
}

bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
                                         unsigned NumOutputs,
                                         ConstraintInfo &Info) const {
  const char *Name = Info.ConstraintStr.c_str();

  while (*Name) {
    switch (*Name) {
    default:
      // Check if we have a matching constraint
      if (*Name >= '0' && *Name <= '9') {
        unsigned i = *Name - '0';

        // Check if matching constraint is out of bounds.
        if (i >= NumOutputs)
          return false;

        // The constraint should have the same info as the respective
        // output constraint.
        Info.setTiedOperand(i, OutputConstraints[i]);
      } else if (!validateAsmConstraint(Name, Info)) {
        // FIXME: This error return is in place temporarily so we can
        // add more constraints as we hit it.  Eventually, an unknown
        // constraint should just be treated as 'g'.
        return false;
      }
      break;
    case '[': {
      unsigned Index = 0;
      if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index))
        return false;

      break;
    }
    case '%': // commutative
      // FIXME: Fail if % is used with the last operand.
      break;
    case 'i': // immediate integer.
    case 'I':
    case 'n': // immediate integer with a known value.
      break;
    case 'r': // general register.
      Info.setAllowsRegister();
      break;
    case 'm': // memory operand.
      Info.setAllowsMemory();
      break;
    case 'g': // general register, memory operand or immediate integer.
    case 'X': // any operand.
      Info.setAllowsRegister();
      Info.setAllowsMemory();
      break;
    }

    Name++;
  }

  return true;
}
<commit_msg>Fix rdar://6860124 - invalid input constraint 'J' in asm This recognizes all the target-independent constant constraints that have target-specific meanings.<commit_after>//===--- TargetInfo.cpp - Information about Target machine ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the TargetInfo and TargetInfoImpl interfaces.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdlib>
using namespace clang;

// TargetInfo Constructor.
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
  // Set defaults.  Defaults are set for a 32-bit RISC platform,
  // like PPC or SPARC.
  // These should be overridden by concrete targets as needed.
  CharIsSigned = true;
  TLSSupported = true;
  PointerWidth = PointerAlign = 32;
  WCharWidth = WCharAlign = 32;
  IntWidth = IntAlign = 32;
  LongWidth = LongAlign = 32;
  LongLongWidth = LongLongAlign = 64;
  FloatWidth = 32;
  FloatAlign = 32;
  DoubleWidth = 64;
  DoubleAlign = 64;
  LongDoubleWidth = 64;
  LongDoubleAlign = 64;
  IntMaxTWidth = 64;
  SizeType = UnsignedLong;
  PtrDiffType = SignedLong;
  IntMaxType = SignedLongLong;
  UIntMaxType = UnsignedLongLong;
  IntPtrType = SignedLong;
  WCharType = SignedInt;
  FloatFormat = &llvm::APFloat::IEEEsingle;
  DoubleFormat = &llvm::APFloat::IEEEdouble;
  LongDoubleFormat = &llvm::APFloat::IEEEdouble;
  DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
                      "i64:64:64-f32:32:32-f64:64:64";
  UserLabelPrefix = "_";
}

// Out of line virtual dtor for TargetInfo.
TargetInfo::~TargetInfo() {}

/// getTypeName - Return the user string for the specified integer type enum.
/// For example, SignedShort -> "short".
const char *TargetInfo::getTypeName(IntType T) {
  switch (T) {
  default: assert(0 && "not an integer!");
  case SignedShort:      return "short";
  case UnsignedShort:    return "unsigned short";
  case SignedInt:        return "int";
  case UnsignedInt:      return "unsigned int";
  case SignedLong:       return "long int";
  case UnsignedLong:     return "long unsigned int";
  case SignedLongLong:   return "long long int";
  case UnsignedLongLong: return "long long unsigned int";
  }
}

//===----------------------------------------------------------------------===//

static void removeGCCRegisterPrefix(const char *&Name) {
  if (Name[0] == '%' || Name[0] == '#')
    Name++;
}

/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
  const char * const *Names;
  unsigned NumNames;

  // Get rid of any register prefix.
  removeGCCRegisterPrefix(Name);

  if (strcmp(Name, "memory") == 0 ||
      strcmp(Name, "cc") == 0)
    return true;

  getGCCRegNames(Names, NumNames);

  // If we have a number it maps to an entry in the register name array.
  if (isdigit(Name[0])) {
    char *End;
    int n = (int)strtol(Name, &End, 0);
    if (*End == 0)
      return n >= 0 && (unsigned)n < NumNames;
  }

  // Check register names.
  for (unsigned i = 0; i < NumNames; i++) {
    if (strcmp(Name, Names[i]) == 0)
      return true;
  }

  // Now check aliases.
  const GCCRegAlias *Aliases;
  unsigned NumAliases;

  getGCCRegAliases(Aliases, NumAliases);
  for (unsigned i = 0; i < NumAliases; i++) {
    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
      if (!Aliases[i].Aliases[j])
        break;
      if (strcmp(Aliases[i].Aliases[j], Name) == 0)
        return true;
    }
  }

  return false;
}

const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
  assert(isValidGCCRegisterName(Name) && "Invalid register passed in");

  removeGCCRegisterPrefix(Name);

  const char * const *Names;
  unsigned NumNames;

  getGCCRegNames(Names, NumNames);

  // First, check if we have a number.
  if (isdigit(Name[0])) {
    char *End;
    int n = (int)strtol(Name, &End, 0);
    if (*End == 0) {
      assert(n >= 0 && (unsigned)n < NumNames &&
             "Out of bounds register number!");
      return Names[n];
    }
  }

  // Now check aliases.
  const GCCRegAlias *Aliases;
  unsigned NumAliases;

  getGCCRegAliases(Aliases, NumAliases);
  for (unsigned i = 0; i < NumAliases; i++) {
    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
      if (!Aliases[i].Aliases[j])
        break;
      if (strcmp(Aliases[i].Aliases[j], Name) == 0)
        return Aliases[i].Register;
    }
  }

  return Name;
}

bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
  const char *Name = Info.getConstraintStr().c_str();
  // An output constraint must start with '=' or '+'
  if (*Name != '=' && *Name != '+')
    return false;

  if (*Name == '+')
    Info.setIsReadWrite();

  Name++;
  while (*Name) {
    switch (*Name) {
    default:
      if (!validateAsmConstraint(Name, Info)) {
        // FIXME: We temporarily return false
        // so we can add more constraints as we hit it.
        // Eventually, an unknown constraint should just be treated as 'g'.
        return false;
      }
    case '&': // early clobber.
      break;
    case 'r': // general register.
      Info.setAllowsRegister();
      break;
    case 'm': // memory operand.
      Info.setAllowsMemory();
      break;
    case 'g': // general register, memory operand or immediate integer.
    case 'X': // any operand.
      Info.setAllowsRegister();
      Info.setAllowsMemory();
      break;
    }

    Name++;
  }

  return true;
}

bool TargetInfo::resolveSymbolicName(const char *&Name,
                                     ConstraintInfo *OutputConstraints,
                                     unsigned NumOutputs,
                                     unsigned &Index) const {
  assert(*Name == '[' && "Symbolic name did not start with '['");
  Name++;
  const char *Start = Name;
  while (*Name && *Name != ']')
    Name++;

  if (!*Name) {
    // Missing ']'
    return false;
  }

  std::string SymbolicName(Start, Name - Start);

  for (Index = 0; Index != NumOutputs; ++Index)
    if (SymbolicName == OutputConstraints[Index].getName())
      return true;

  return false;
}

bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
                                         unsigned NumOutputs,
                                         ConstraintInfo &Info) const {
  const char *Name = Info.ConstraintStr.c_str();

  while (*Name) {
    switch (*Name) {
    default:
      // Check if we have a matching constraint
      if (*Name >= '0' && *Name <= '9') {
        unsigned i = *Name - '0';

        // Check if matching constraint is out of bounds.
        if (i >= NumOutputs)
          return false;

        // The constraint should have the same info as the respective
        // output constraint.
        Info.setTiedOperand(i, OutputConstraints[i]);
      } else if (!validateAsmConstraint(Name, Info)) {
        // FIXME: This error return is in place temporarily so we can
        // add more constraints as we hit it.  Eventually, an unknown
        // constraint should just be treated as 'g'.
        return false;
      }
      break;
    case '[': {
      unsigned Index = 0;
      if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index))
        return false;

      break;
    }
    case '%': // commutative
      // FIXME: Fail if % is used with the last operand.
      break;
    case 'i': // immediate integer.
    case 'n': // immediate integer with a known value.
      break;
    case 'I':  // Various constant constraints with target-specific meanings.
    case 'J':
    case 'K':
    case 'L':
    case 'M':
    case 'N':
    case 'O':
    case 'P':
      break;
    case 'r': // general register.
      Info.setAllowsRegister();
      break;
    case 'm': // memory operand.
      Info.setAllowsMemory();
      break;
    case 'g': // general register, memory operand or immediate integer.
    case 'X': // any operand.
      Info.setAllowsRegister();
      Info.setAllowsMemory();
      break;
    }

    Name++;
  }

  return true;
}
<|endoftext|>


<commit_before>//===--- TargetInfo.cpp - Information about Target machine ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the TargetInfo and TargetInfoImpl interfaces.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdlib>
using namespace clang;

// TargetInfo Constructor.
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
  // Set defaults.  Defaults are set for a 32-bit RISC platform,
  // like PPC or SPARC.
  // These should be overridden by concrete targets as needed.
  CharIsSigned = true;
  PointerWidth = PointerAlign = 32;
  WCharWidth = WCharAlign = 32;
  IntWidth = IntAlign = 32;
  LongWidth = LongAlign = 32;
  LongLongWidth = LongLongAlign = 64;
  FloatWidth = 32;
  FloatAlign = 32;
  DoubleWidth = 64;
  DoubleAlign = 64;
  LongDoubleWidth = 64;
  LongDoubleAlign = 64;
  FloatFormat = &llvm::APFloat::IEEEsingle;
  DoubleFormat = &llvm::APFloat::IEEEdouble;
  LongDoubleFormat = &llvm::APFloat::IEEEdouble;
  DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
                      "i64:64:64-f32:32:32-f64:64:64";
}

// Out of line virtual dtor for TargetInfo.
TargetInfo::~TargetInfo() {}

//===----------------------------------------------------------------------===//

static void removeGCCRegisterPrefix(const char *&Name) {
  if (Name[0] == '%' || Name[0] == '#')
    Name++;
}

/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
  const char * const *Names;
  unsigned NumNames;

  // Get rid of any register prefix.
  removeGCCRegisterPrefix(Name);

  if (strcmp(Name, "memory") == 0 ||
      strcmp(Name, "cc") == 0)
    return true;

  getGCCRegNames(Names, NumNames);

  // If we have a number it maps to an entry in the register name array.
  if (isdigit(Name[0])) {
    char *End;
    int n = (int)strtol(Name, &End, 0);
    if (*End == 0)
      return n >= 0 && (unsigned)n < NumNames;
  }

  // Check register names.
  for (unsigned i = 0; i < NumNames; i++) {
    if (strcmp(Name, Names[i]) == 0)
      return true;
  }

  // Now check aliases.
  const GCCRegAlias *Aliases;
  unsigned NumAliases;

  getGCCRegAliases(Aliases, NumAliases);
  for (unsigned i = 0; i < NumAliases; i++) {
    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
      if (!Aliases[i].Aliases[j])
        break;
      if (strcmp(Aliases[i].Aliases[j], Name) == 0)
        return true;
    }
  }

  return false;
}

const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
  assert(isValidGCCRegisterName(Name) && "Invalid register passed in");

  removeGCCRegisterPrefix(Name);

  const char * const *Names;
  unsigned NumNames;

  getGCCRegNames(Names, NumNames);

  // First, check if we have a number.
  if (isdigit(Name[0])) {
    char *End;
    int n = (int)strtol(Name, &End, 0);
    if (*End == 0) {
      assert(n >= 0 && (unsigned)n < NumNames &&
             "Out of bounds register number!");
      return Names[n];
    }
  }

  // Now check aliases.
  const GCCRegAlias *Aliases;
  unsigned NumAliases;

  getGCCRegAliases(Aliases, NumAliases);
  for (unsigned i = 0; i < NumAliases; i++) {
    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
      if (!Aliases[i].Aliases[j])
        break;
      if (strcmp(Aliases[i].Aliases[j], Name) == 0)
        return Aliases[i].Register;
    }
  }

  return Name;
}

bool TargetInfo::validateOutputConstraint(const char *Name,
                                          ConstraintInfo &info) const
{
  // An output constraint must start with '=' or '+'
  if (*Name != '=' && *Name != '+')
    return false;

  if (*Name == '+')
    info = CI_ReadWrite;
  else
    info = CI_None;

  Name++;
  while (*Name) {
    switch (*Name) {
    default:
      if (!validateAsmConstraint(*Name, info)) {
        // FIXME: We temporarily return false
        // so we can add more constraints as we hit it.
        // Eventually, an unknown constraint should just be treated as 'g'.
        return false;
      }
    case '&': // early clobber.
      break;
    case 'r': // general register.
      info = (ConstraintInfo)(info|CI_AllowsRegister);
      break;
    case 'm': // memory operand.
      info = (ConstraintInfo)(info|CI_AllowsMemory);
      break;
    case 'g': // general register, memory operand or immediate integer.
      info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
      break;
    }

    Name++;
  }

  return true;
}

bool TargetInfo::validateInputConstraint(const char *Name,
                                         unsigned NumOutputs,
                                         ConstraintInfo &info) const {
  while (*Name) {
    switch (*Name) {
    default:
      // Check if we have a matching constraint
      if (*Name >= '0' && *Name <= '9') {
        unsigned i = *Name - '0';

        // Check if matching constraint is out of bounds.
        if (i >= NumOutputs)
          return false;
      } else if (!validateAsmConstraint(*Name, info)) {
        // FIXME: This assert is in place temporarily
        // so we can add more constraints as we hit it.
        // Eventually, an unknown constraint should just be treated as 'g'.
        assert(0 && "Unknown input constraint type!");
      }
    case '%': // commutative
      // FIXME: Fail if % is used with the last operand.
      break;
    case 'i': // immediate integer.
    case 'I':
    case 'n': // immediate integer with a known value.
      break;
    case 'r': // general register.
      info = (ConstraintInfo)(info|CI_AllowsRegister);
      break;
    case 'm': // memory operand.
      info = (ConstraintInfo)(info|CI_AllowsMemory);
      break;
    case 'g': // general register, memory operand or immediate integer.
      info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
      break;
    }

    Name++;
  }

  return true;
}
<commit_msg>Stop asserting in TargetInfo::validateInputConstraint  - Sema gives a perfectively nice error message on invalid constraints.<commit_after>//===--- TargetInfo.cpp - Information about Target machine ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the TargetInfo and TargetInfoImpl interfaces.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdlib>
using namespace clang;

// TargetInfo Constructor.
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
  // Set defaults.  Defaults are set for a 32-bit RISC platform,
  // like PPC or SPARC.
  // These should be overridden by concrete targets as needed.
  CharIsSigned = true;
  PointerWidth = PointerAlign = 32;
  WCharWidth = WCharAlign = 32;
  IntWidth = IntAlign = 32;
  LongWidth = LongAlign = 32;
  LongLongWidth = LongLongAlign = 64;
  FloatWidth = 32;
  FloatAlign = 32;
  DoubleWidth = 64;
  DoubleAlign = 64;
  LongDoubleWidth = 64;
  LongDoubleAlign = 64;
  FloatFormat = &llvm::APFloat::IEEEsingle;
  DoubleFormat = &llvm::APFloat::IEEEdouble;
  LongDoubleFormat = &llvm::APFloat::IEEEdouble;
  DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
                      "i64:64:64-f32:32:32-f64:64:64";
}

// Out of line virtual dtor for TargetInfo.
TargetInfo::~TargetInfo() {}

//===----------------------------------------------------------------------===//

static void removeGCCRegisterPrefix(const char *&Name) {
  if (Name[0] == '%' || Name[0] == '#')
    Name++;
}

/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
  const char * const *Names;
  unsigned NumNames;

  // Get rid of any register prefix.
  removeGCCRegisterPrefix(Name);

  if (strcmp(Name, "memory") == 0 ||
      strcmp(Name, "cc") == 0)
    return true;

  getGCCRegNames(Names, NumNames);

  // If we have a number it maps to an entry in the register name array.
  if (isdigit(Name[0])) {
    char *End;
    int n = (int)strtol(Name, &End, 0);
    if (*End == 0)
      return n >= 0 && (unsigned)n < NumNames;
  }

  // Check register names.
  for (unsigned i = 0; i < NumNames; i++) {
    if (strcmp(Name, Names[i]) == 0)
      return true;
  }

  // Now check aliases.
  const GCCRegAlias *Aliases;
  unsigned NumAliases;

  getGCCRegAliases(Aliases, NumAliases);
  for (unsigned i = 0; i < NumAliases; i++) {
    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
      if (!Aliases[i].Aliases[j])
        break;
      if (strcmp(Aliases[i].Aliases[j], Name) == 0)
        return true;
    }
  }

  return false;
}

const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
  assert(isValidGCCRegisterName(Name) && "Invalid register passed in");

  removeGCCRegisterPrefix(Name);

  const char * const *Names;
  unsigned NumNames;

  getGCCRegNames(Names, NumNames);

  // First, check if we have a number.
  if (isdigit(Name[0])) {
    char *End;
    int n = (int)strtol(Name, &End, 0);
    if (*End == 0) {
      assert(n >= 0 && (unsigned)n < NumNames &&
             "Out of bounds register number!");
      return Names[n];
    }
  }

  // Now check aliases.
  const GCCRegAlias *Aliases;
  unsigned NumAliases;

  getGCCRegAliases(Aliases, NumAliases);
  for (unsigned i = 0; i < NumAliases; i++) {
    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
      if (!Aliases[i].Aliases[j])
        break;
      if (strcmp(Aliases[i].Aliases[j], Name) == 0)
        return Aliases[i].Register;
    }
  }

  return Name;
}

bool TargetInfo::validateOutputConstraint(const char *Name,
                                          ConstraintInfo &info) const
{
  // An output constraint must start with '=' or '+'
  if (*Name != '=' && *Name != '+')
    return false;

  if (*Name == '+')
    info = CI_ReadWrite;
  else
    info = CI_None;

  Name++;
  while (*Name) {
    switch (*Name) {
    default:
      if (!validateAsmConstraint(*Name, info)) {
        // FIXME: We temporarily return false
        // so we can add more constraints as we hit it.
        // Eventually, an unknown constraint should just be treated as 'g'.
        return false;
      }
    case '&': // early clobber.
      break;
    case 'r': // general register.
      info = (ConstraintInfo)(info|CI_AllowsRegister);
      break;
    case 'm': // memory operand.
      info = (ConstraintInfo)(info|CI_AllowsMemory);
      break;
    case 'g': // general register, memory operand or immediate integer.
      info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
      break;
    }

    Name++;
  }

  return true;
}

bool TargetInfo::validateInputConstraint(const char *Name,
                                         unsigned NumOutputs,
                                         ConstraintInfo &info) const {
  while (*Name) {
    switch (*Name) {
    default:
      // Check if we have a matching constraint
      if (*Name >= '0' && *Name <= '9') {
        unsigned i = *Name - '0';

        // Check if matching constraint is out of bounds.
        if (i >= NumOutputs)
          return false;
      } else if (!validateAsmConstraint(*Name, info)) {
        // FIXME: This error return is in place temporarily so we can
        // add more constraints as we hit it.  Eventually, an unknown
        // constraint should just be treated as 'g'.
        return false;
      }
    case '%': // commutative
      // FIXME: Fail if % is used with the last operand.
      break;
    case 'i': // immediate integer.
    case 'I':
    case 'n': // immediate integer with a known value.
      break;
    case 'r': // general register.
      info = (ConstraintInfo)(info|CI_AllowsRegister);
      break;
    case 'm': // memory operand.
      info = (ConstraintInfo)(info|CI_AllowsMemory);
      break;
    case 'g': // general register, memory operand or immediate integer.
      info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
      break;
    }

    Name++;
  }

  return true;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2016, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "EndpointSrv.h"

#ifndef _WIN32

#define BIND_4_COMPAT 1  // LINUX
#define BIND_8_COMPAT 1  // MACOSX

#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>

#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "Rest/EndpointIp.h"

using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;

#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
#define MAXPACKET 1024
#endif

union QueryBuffer {
  ::HEADER header;
  unsigned char buffer[MAXPACKET];
};

struct SrvRecord {
  int priority;
  int weight;
  int port;
  std::string name;
};

std::vector<SrvRecord> srvRecords(std::string specification) {
  res_init();

  char const* dname = specification.c_str();
  int nclass = ns_c_in;
  int type = ns_t_srv;

  QueryBuffer answer;
  int anslen = sizeof(answer);

  int n = res_search(dname, nclass, type, answer.buffer, anslen);

  std::vector<SrvRecord> services;

  if (n != -1) {
    HEADER* hp = &answer.header;

    int qdcount = ntohs(hp->qdcount);
    int ancount = ntohs(hp->ancount);

    unsigned char* msg = answer.buffer;
    unsigned char* eom = msg + n;
    unsigned char* cp = msg + sizeof(HEADER);

    unsigned char hostbuf[256];

    while (0 < qdcount-- && cp < eom) {
      n = dn_expand(msg, eom, cp, (char*)hostbuf, 256);

      if (n < 0) {
        LOG(WARN) << "DNS record for '" << specification << "' is corrupt";
        return {};
      }

      cp += n + QFIXEDSZ;
    }

    // loop through the answer buffer and extract SRV records
    while (0 < ancount-- && cp < eom) {
      n = dn_expand(msg, eom, cp, (char*)hostbuf, 256);

      if (n < 0) {
        LOG(WARN) << "DNS record for '" << specification << "' is corrupt";
        return {};
      }

      cp += n;

      int type = _getshort(cp);
      cp += 2;

      int nclass = _getshort(cp);
      cp += 2;

      int ttl = _getlong(cp);
      cp += 4;

      int dlen = _getshort(cp);
      cp += 2;

      int priority = _getshort(cp);
      cp += 2;

      int weight = _getshort(cp);
      cp += 2;

      int port = _getshort(cp);
      cp += 2;

      n = dn_expand(msg, eom, cp, (char*)hostbuf, 256);

      if (n < 0) {
        LOG(WARN) << "DNS record for '" << specification << "' is corrupt";
        break;
      }

      cp += n;

      LOG(TRACE) << "DNS record for '" << specification << "': type " << type
                 << ", class " << nclass << ", ttl " << ttl << ", len " << dlen
                 << ", prio " << priority << ", weight " << weight << ", port "
                 << port << ", host '" << hostbuf << "'";

      if (type != T_SRV) {
        continue;
      }

      SrvRecord srv;

      srv.weight = weight;
      srv.priority = priority;
      srv.port = port;
      srv.name = (char*)hostbuf;

      services.push_back(srv);
    }
  } else {
    LOG(WARN) << "DNS record for '" << specification << "' not found";
  }

  std::sort(services.begin(), services.end(),
            [](SrvRecord const& lhs, SrvRecord const& rhs) {
              if (lhs.priority != rhs.priority) {
                return lhs.priority < rhs.priority;
              }

              return lhs.weight > rhs.weight;
            });

  return services;
}

#else

std::vector<SrvRecord> srvRecords(std::string specification) { return {}; }

#endif

EndpointSrv::EndpointSrv(std::string const& specification)
    : Endpoint(ENDPOINT_CLIENT, DOMAIN_SRV, ENCRYPTION_NONE, specification, 0) {
}

EndpointSrv::~EndpointSrv() {}

bool EndpointSrv::isConnected() const {
  if (_endpoint != nullptr) {
    return _endpoint->isConnected();
  }

  return false;
}

TRI_socket_t EndpointSrv::connect(double connectTimeout,
                                  double requestTimeout) {
  auto services = srvRecords(_specification);

  TRI_socket_t res;

  for (auto service : services) {
    std::string spec =
        "tcp://" + service.name + ":" + StringUtils::itoa(service.port);

    _endpoint.reset(Endpoint::clientFactory(spec));

    res = _endpoint->connect(connectTimeout, requestTimeout);

    if (_endpoint->isConnected()) {
      return res;
    }
  }

  TRI_invalidatesocket(&res);
  return res;
}

void EndpointSrv::disconnect() {
  if (_endpoint != nullptr) {
    _endpoint->disconnect();
  }
}

bool EndpointSrv::initIncoming(TRI_socket_t) { return false; }

int EndpointSrv::getDomain() const {
  if (_endpoint != nullptr) {
    return _endpoint->getDomain();
  }

  return -1;
}

int EndpointSrv::getPort() const {
  if (_endpoint != nullptr) {
    return _endpoint->getPort();
  }

  return -1;
}

std::string EndpointSrv::getHost() const {
  if (_endpoint != nullptr) {
    return _endpoint->getHost();
  }

  return "";
}

std::string EndpointSrv::getHostString() const {
  if (_endpoint != nullptr) {
    return _endpoint->getHostString();
  }

  return "";
}
<commit_msg>switch to GETLONG<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2016, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "EndpointSrv.h"

#ifndef _WIN32

#define BIND_4_COMPAT 1  // LINUX
#define BIND_8_COMPAT 1  // MACOSX

#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>

#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "Rest/EndpointIp.h"

using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;

#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
#define MAXPACKET 1024
#endif

union QueryBuffer {
  ::HEADER header;
  unsigned char buffer[MAXPACKET];
};

struct SrvRecord {
  int priority;
  int weight;
  int port;
  std::string name;
};

std::vector<SrvRecord> srvRecords(std::string specification) {
  res_init();

  char const* dname = specification.c_str();
  int nclass = ns_c_in;
  int type = ns_t_srv;

  QueryBuffer answer;
  int anslen = sizeof(answer);

  int n = res_search(dname, nclass, type, answer.buffer, anslen);

  std::vector<SrvRecord> services;

  if (n != -1) {
    HEADER* hp = &answer.header;

    int qdcount = ntohs(hp->qdcount);
    int ancount = ntohs(hp->ancount);

    unsigned char* msg = answer.buffer;
    unsigned char* eom = msg + n;
    unsigned char* cp = msg + sizeof(HEADER);

    unsigned char hostbuf[256];

    while (0 < qdcount-- && cp < eom) {
      n = dn_expand(msg, eom, cp, (char*)hostbuf, 256);

      if (n < 0) {
        LOG(WARN) << "DNS record for '" << specification << "' is corrupt";
        return {};
      }

      cp += n + QFIXEDSZ;
    }

    // loop through the answer buffer and extract SRV records
    while (0 < ancount-- && cp < eom) {
      n = dn_expand(msg, eom, cp, (char*)hostbuf, 256);

      if (n < 0) {
        LOG(WARN) << "DNS record for '" << specification << "' is corrupt";
        return {};
      }

      cp += n;

      int type;
      GETSHORT(type, cp);

      int nclass;
      GETSHORT(nclass, cp);

      int ttl;
      GETLONG(ttl, cp);

      int dlen;
      GETSHORT(dlen, cp);

      int priority;
      GETSHORT(priority, cp);

      int weight;
      GETSHORT(weight, cp);

      int port;
      GETSHORT(port, cp);

      n = dn_expand(msg, eom, cp, (char*)hostbuf, 256);

      if (n < 0) {
        LOG(WARN) << "DNS record for '" << specification << "' is corrupt";
        break;
      }

      cp += n;

      LOG(TRACE) << "DNS record for '" << specification << "': type " << type
                 << ", class " << nclass << ", ttl " << ttl << ", len " << dlen
                 << ", prio " << priority << ", weight " << weight << ", port "
                 << port << ", host '" << hostbuf << "'";

      if (type != T_SRV) {
        continue;
      }

      SrvRecord srv;

      srv.weight = weight;
      srv.priority = priority;
      srv.port = port;
      srv.name = (char*)hostbuf;

      services.push_back(srv);
    }
  } else {
    LOG(WARN) << "DNS record for '" << specification << "' not found";
  }

  std::sort(services.begin(), services.end(),
            [](SrvRecord const& lhs, SrvRecord const& rhs) {
              if (lhs.priority != rhs.priority) {
                return lhs.priority < rhs.priority;
              }

              return lhs.weight > rhs.weight;
            });

  return services;
}

#else

std::vector<SrvRecord> srvRecords(std::string specification) { return {}; }

#endif

EndpointSrv::EndpointSrv(std::string const& specification)
    : Endpoint(ENDPOINT_CLIENT, DOMAIN_SRV, ENCRYPTION_NONE, specification, 0) {
}

EndpointSrv::~EndpointSrv() {}

bool EndpointSrv::isConnected() const {
  if (_endpoint != nullptr) {
    return _endpoint->isConnected();
  }

  return false;
}

TRI_socket_t EndpointSrv::connect(double connectTimeout,
                                  double requestTimeout) {
  auto services = srvRecords(_specification);

  TRI_socket_t res;

  for (auto service : services) {
    std::string spec =
        "tcp://" + service.name + ":" + StringUtils::itoa(service.port);

    _endpoint.reset(Endpoint::clientFactory(spec));

    res = _endpoint->connect(connectTimeout, requestTimeout);

    if (_endpoint->isConnected()) {
      return res;
    }
  }

  TRI_invalidatesocket(&res);
  return res;
}

void EndpointSrv::disconnect() {
  if (_endpoint != nullptr) {
    _endpoint->disconnect();
  }
}

bool EndpointSrv::initIncoming(TRI_socket_t) { return false; }

int EndpointSrv::getDomain() const {
  if (_endpoint != nullptr) {
    return _endpoint->getDomain();
  }

  return -1;
}

int EndpointSrv::getPort() const {
  if (_endpoint != nullptr) {
    return _endpoint->getPort();
  }

  return -1;
}

std::string EndpointSrv::getHost() const {
  if (_endpoint != nullptr) {
    return _endpoint->getHost();
  }

  return "";
}

std::string EndpointSrv::getHostString() const {
  if (_endpoint != nullptr) {
    return _endpoint->getHostString();
  }

  return "";
}
<|endoftext|>


<commit_before>//  Author:Frankie.Chu
//  Date:9 April,2012
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//
//  Modified record:
//
/*******************************************************************************/
#include "TM1637.h"
#include <Wyliodrin.h>
static int8_t TubeTab[] = {0x3f,0x06,0x5b,0x4f,
                           0x66,0x6d,0x7d,0x07,
                           0x7f,0x6f,0x77,0x7c,
                           0x39,0x5e,0x79,0x71};//0~9,A,b,C,d,E,F
TM1637::TM1637(uint8_t Clk, uint8_t Data)
{
  Clkpin = Clk;
  Datapin = Data;
  pinMode(Clkpin,OUTPUT);
  pinMode(Datapin,OUTPUT);
}

void TM1637::init(void)
{
  clearDisplay();
}

void TM1637::writeByte(int8_t wr_data)
{
  uint8_t i,count1;
  for(i=0;i<8;i++)        //sent 8bit data
  {
    digitalWrite(Clkpin,LOW);
    if(wr_data & 0x01)digitalWrite(Datapin,HIGH);//LSB first
    else digitalWrite(Datapin,LOW);
    wr_data >>= 1;
    digitalWrite(Clkpin,HIGH);

  }
  digitalWrite(Clkpin,LOW); //wait for the ACK
  digitalWrite(Datapin,HIGH);
  digitalWrite(Clkpin,HIGH);
  pinMode(Datapin,INPUT);
  while(digitalRead(Datapin))
  {
    count1 +=1;
    if(count1 == 200)//
    {
     pinMode(Datapin,OUTPUT);
     digitalWrite(Datapin,LOW);
     count1 =0;
    }
    pinMode(Datapin,INPUT);
  }
  pinMode(Datapin,OUTPUT);

}
//send start signal to TM1637
void TM1637::start(void)
{
  digitalWrite(Clkpin,HIGH);//send start signal to TM1637
  digitalWrite(Datapin,HIGH);
  digitalWrite(Datapin,LOW);
  digitalWrite(Clkpin,LOW);
}
//End of transmission
void TM1637::stop(void)
{
  digitalWrite(Clkpin,LOW);
  digitalWrite(Datapin,LOW);
  digitalWrite(Clkpin,HIGH);
  digitalWrite(Datapin,HIGH);
}
//display function.Write to full-screen.
void TM1637::display(int8_t DispData[])
{
  int8_t SegData[4];
  uint8_t i;
  for(i = 0;i < 4;i ++)
  {
    SegData[i] = DispData[i];
  }
  coding(SegData);
  start();          //start signal sent to TM1637 from MCU
  writeByte(ADDR_AUTO);//
  stop();           //
  start();          //
  writeByte(Cmd_SetAddr);//
  for(i=0;i < 4;i ++)
  {
    writeByte(SegData[i]);        //
  }
  stop();           //
  start();          //
  writeByte(Cmd_DispCtrl);//
  stop();           //
}
//******************************************
void TM1637::display(uint8_t BitAddr,int8_t DispData)
{
  int8_t SegData;
  SegData = coding(DispData);
  start();          //start signal sent to TM1637 from MCU
  writeByte(ADDR_FIXED);//
  stop();           //
  start();          //
  writeByte(BitAddr|0xc0);//
  writeByte(SegData);//
  stop();            //
  start();          //
  writeByte(Cmd_DispCtrl);//
  stop();           //
}

void TM1637::clearDisplay(void)
{
  display(0x00,0x7f);
  display(0x01,0x7f);
  display(0x02,0x7f);
  display(0x03,0x7f);
}
//To take effect the next time it displays.
void TM1637::set(uint8_t brightness,uint8_t SetData,uint8_t SetAddr)
{
  Cmd_SetData = SetData;
  Cmd_SetAddr = SetAddr;
  Cmd_DispCtrl = 0x88 + brightness;//Set the brightness and it takes effect the next time it displays.
}

//Whether to light the clock point ":".
//To take effect the next time it displays.
void TM1637::point(boolean PointFlag)
{
  _PointFlag = PointFlag;
}
void TM1637::coding(int8_t DispData[])
{
  uint8_t PointData;
  if(_PointFlag == POINT_ON)PointData = 0x80;
  else PointData = 0;
  for(uint8_t i = 0;i < 4;i ++)
  {
    if(DispData[i] == 0x7f)DispData[i] = 0x00;
    else DispData[i] = TubeTab[DispData[i]] + PointData;
  }
}
int8_t TM1637::coding(int8_t DispData)
{
  uint8_t PointData;
  if(_PointFlag == POINT_ON)PointData = 0x80;
  else PointData = 0;
  if(DispData == 0x7f) DispData = 0x00 + PointData;//The bit digital tube off
  else DispData = TubeTab[DispData] + PointData;
  return DispData;
}
<commit_msg>Update TM1637.cpp<commit_after>//  Author:Frankie.Chu
//  Date:9 April,2012
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//
//  Modified record:
//
/*******************************************************************************/
#include "TM1637.h"
#include "../wiring/wiring.h"
static int8_t TubeTab[] = {0x3f,0x06,0x5b,0x4f,
                           0x66,0x6d,0x7d,0x07,
                           0x7f,0x6f,0x77,0x7c,
                           0x39,0x5e,0x79,0x71};//0~9,A,b,C,d,E,F
TM1637::TM1637(uint8_t Clk, uint8_t Data)
{
  Clkpin = Clk;
  Datapin = Data;
  pinMode(Clkpin,OUTPUT);
  pinMode(Datapin,OUTPUT);
}

void TM1637::init(void)
{
  clearDisplay();
}

void TM1637::writeByte(int8_t wr_data)
{
  uint8_t i,count1;
  for(i=0;i<8;i++)        //sent 8bit data
  {
    digitalWrite(Clkpin,LOW);
    if(wr_data & 0x01)digitalWrite(Datapin,HIGH);//LSB first
    else digitalWrite(Datapin,LOW);
    wr_data >>= 1;
    digitalWrite(Clkpin,HIGH);

  }
  digitalWrite(Clkpin,LOW); //wait for the ACK
  digitalWrite(Datapin,HIGH);
  digitalWrite(Clkpin,HIGH);
  pinMode(Datapin,INPUT);
  while(digitalRead(Datapin))
  {
    count1 +=1;
    if(count1 == 200)//
    {
     pinMode(Datapin,OUTPUT);
     digitalWrite(Datapin,LOW);
     count1 =0;
    }
    pinMode(Datapin,INPUT);
  }
  pinMode(Datapin,OUTPUT);

}
//send start signal to TM1637
void TM1637::start(void)
{
  digitalWrite(Clkpin,HIGH);//send start signal to TM1637
  digitalWrite(Datapin,HIGH);
  digitalWrite(Datapin,LOW);
  digitalWrite(Clkpin,LOW);
}
//End of transmission
void TM1637::stop(void)
{
  digitalWrite(Clkpin,LOW);
  digitalWrite(Datapin,LOW);
  digitalWrite(Clkpin,HIGH);
  digitalWrite(Datapin,HIGH);
}
//display function.Write to full-screen.
void TM1637::display(int8_t DispData[])
{
  int8_t SegData[4];
  uint8_t i;
  for(i = 0;i < 4;i ++)
  {
    SegData[i] = DispData[i];
  }
  coding(SegData);
  start();          //start signal sent to TM1637 from MCU
  writeByte(ADDR_AUTO);//
  stop();           //
  start();          //
  writeByte(Cmd_SetAddr);//
  for(i=0;i < 4;i ++)
  {
    writeByte(SegData[i]);        //
  }
  stop();           //
  start();          //
  writeByte(Cmd_DispCtrl);//
  stop();           //
}
//******************************************
void TM1637::display(uint8_t BitAddr,int8_t DispData)
{
  int8_t SegData;
  SegData = coding(DispData);
  start();          //start signal sent to TM1637 from MCU
  writeByte(ADDR_FIXED);//
  stop();           //
  start();          //
  writeByte(BitAddr|0xc0);//
  writeByte(SegData);//
  stop();            //
  start();          //
  writeByte(Cmd_DispCtrl);//
  stop();           //
}

void TM1637::clearDisplay(void)
{
  display(0x00,0x7f);
  display(0x01,0x7f);
  display(0x02,0x7f);
  display(0x03,0x7f);
}
//To take effect the next time it displays.
void TM1637::set(uint8_t brightness,uint8_t SetData,uint8_t SetAddr)
{
  Cmd_SetData = SetData;
  Cmd_SetAddr = SetAddr;
  Cmd_DispCtrl = 0x88 + brightness;//Set the brightness and it takes effect the next time it displays.
}

//Whether to light the clock point ":".
//To take effect the next time it displays.
void TM1637::point(boolean PointFlag)
{
  _PointFlag = PointFlag;
}
void TM1637::coding(int8_t DispData[])
{
  uint8_t PointData;
  if(_PointFlag == POINT_ON)PointData = 0x80;
  else PointData = 0;
  for(uint8_t i = 0;i < 4;i ++)
  {
    if(DispData[i] == 0x7f)DispData[i] = 0x00;
    else DispData[i] = TubeTab[DispData[i]] + PointData;
  }
}
int8_t TM1637::coding(int8_t DispData)
{
  uint8_t PointData;
  if(_PointFlag == POINT_ON)PointData = 0x80;
  else PointData = 0;
  if(DispData == 0x7f) DispData = 0x00 + PointData;//The bit digital tube off
  else DispData = TubeTab[DispData] + PointData;
  return DispData;
}
<|endoftext|>


<commit_before>//===-- InlineAsm.cpp - Implement the InlineAsm class ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the InlineAsm class.
//
//===----------------------------------------------------------------------===//

#include "llvm/InlineAsm.h"
#include "llvm/DerivedTypes.h"
#include <algorithm>
#include <cctype>
using namespace llvm;

// NOTE: when memoizing the function type, we have to be careful to handle the
// case when the type gets refined.

InlineAsm *InlineAsm::get(const FunctionType *Ty, const std::string &AsmString,
                          const std::string &Constraints, bool hasSideEffects) {
  // FIXME: memoize!
  return new InlineAsm(Ty, AsmString, Constraints, hasSideEffects);
}

InlineAsm::InlineAsm(const FunctionType *Ty, const std::string &asmString,
                     const std::string &constraints, bool hasSideEffects)
  : Value(PointerType::get(Ty), Value::InlineAsmVal), AsmString(asmString),
    Constraints(constraints), HasSideEffects(hasSideEffects) {

  // Do various checks on the constraint string and type.
  assert(Verify(Ty, constraints) && "Function type not legal for constraints!");
}

const FunctionType *InlineAsm::getFunctionType() const {
  return cast<FunctionType>(getType()->getElementType());
}

/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
/// fields in this structure.  If the constraint string is not understood,
/// return true, otherwise return false.
bool InlineAsm::ConstraintInfo::Parse(const std::string &Str,
                     std::vector<InlineAsm::ConstraintInfo> &ConstraintsSoFar) {
  std::string::const_iterator I = Str.begin(), E = Str.end();

  // Initialize
  Type = isInput;
  isEarlyClobber = false;
  isIndirectOutput = false;
  hasMatchingInput = false;

  // Parse the prefix.
  if (*I == '~') {
    Type = isClobber;
    ++I;
  } else if (*I == '=') {
    ++I;
    Type = isOutput;
    if (I != E && *I == '=') {
      isIndirectOutput = true;
      ++I;
    }
  }

  if (I == E) return true;  // Just a prefix, like "==" or "~".

  // Parse the modifiers.
  bool DoneWithModifiers = false;
  while (!DoneWithModifiers) {
    switch (*I) {
    default:
      DoneWithModifiers = true;
      break;
    case '&':
      if (Type != isOutput ||      // Cannot early clobber anything but output.
          isEarlyClobber)          // Reject &&&&&&
        return true;
      isEarlyClobber = true;
      break;
    }

    if (!DoneWithModifiers) {
      ++I;
      if (I == E) return true;   // Just prefixes and modifiers!
    }
  }

  // Parse the various constraints.
  while (I != E) {
    if (*I == '{') {   // Physical register reference.
      // Find the end of the register name.
      std::string::const_iterator ConstraintEnd = std::find(I+1, E, '}');
      if (ConstraintEnd == E) return true;  // "{foo"
      Codes.push_back(std::string(I, ConstraintEnd+1));
      I = ConstraintEnd+1;
    } else if (isdigit(*I)) {     // Matching Constraint
      // Maximal munch numbers.
      std::string::const_iterator NumStart = I;
      while (I != E && isdigit(*I))
        ++I;
      Codes.push_back(std::string(NumStart, I));
      unsigned N = atoi(Codes.back().c_str());
      // Check that this is a valid matching constraint!
      if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||
          Type != isInput)
        return true;  // Invalid constraint number.

      // Note that operand #n has a matching input.
      ConstraintsSoFar[N].hasMatchingInput = true;
    } else {
      // Single letter constraint.
      Codes.push_back(std::string(I, I+1));
      ++I;
    }
  }

  return false;
}

std::vector<InlineAsm::ConstraintInfo>
InlineAsm::ParseConstraints(const std::string &Constraints) {
  std::vector<ConstraintInfo> Result;

  // Scan the constraints string.
  for (std::string::const_iterator I = Constraints.begin(),
       E = Constraints.end(); I != E; ) {
    ConstraintInfo Info;

    // Find the end of this constraint.
    std::string::const_iterator ConstraintEnd = std::find(I, E, ',');

    if (ConstraintEnd == I ||  // Empty constraint like ",,"
        Info.Parse(std::string(I, ConstraintEnd), Result)) {
      Result.clear();          // Erroneous constraint?
      break;
    }

    Result.push_back(Info);

    // ConstraintEnd may be either the next comma or the end of the string.  In
    // the former case, we skip the comma.
    I = ConstraintEnd;
    if (I != E) {
      ++I;
      if (I == E) { Result.clear(); break; }    // don't allow "xyz,"
    }
  }

  return Result;
}

/// Verify - Verify that the specified constraint string is reasonable for the
/// specified function type, and otherwise validate the constraint string.
bool InlineAsm::Verify(const FunctionType *Ty, const std::string &ConstStr) {
  if (Ty->isVarArg()) return false;

  std::vector<ConstraintInfo> Constraints = ParseConstraints(ConstStr);

  // Error parsing constraints.
  if (Constraints.empty() && !ConstStr.empty()) return false;

  unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;

  for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
    switch (Constraints[i].Type) {
    case InlineAsm::isOutput:
      if (!Constraints[i].isIndirectOutput) {
        if (NumInputs || NumClobbers) return false;  // outputs come first.
        ++NumOutputs;
        break;
      }
      // FALLTHROUGH for IndirectOutputs.
    case InlineAsm::isInput:
      if (NumClobbers) return false;               // inputs before clobbers.
      ++NumInputs;
      break;
    case InlineAsm::isClobber:
      ++NumClobbers;
      break;
    }
  }

  if (NumOutputs > 1) return false;  // Only one result allowed so far.

  if ((Ty->getReturnType() != Type::VoidTy) != NumOutputs)
    return false;   // NumOutputs = 1 iff has a result type.

  if (Ty->getNumParams() != NumInputs) return false;
  return true;
}
<commit_msg>Parse the %*# constraint modifiers<commit_after>//===-- InlineAsm.cpp - Implement the InlineAsm class ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the InlineAsm class.
//
//===----------------------------------------------------------------------===//

#include "llvm/InlineAsm.h"
#include "llvm/DerivedTypes.h"
#include <algorithm>
#include <cctype>
using namespace llvm;

// NOTE: when memoizing the function type, we have to be careful to handle the
// case when the type gets refined.

InlineAsm *InlineAsm::get(const FunctionType *Ty, const std::string &AsmString,
                          const std::string &Constraints, bool hasSideEffects) {
  // FIXME: memoize!
  return new InlineAsm(Ty, AsmString, Constraints, hasSideEffects);
}

InlineAsm::InlineAsm(const FunctionType *Ty, const std::string &asmString,
                     const std::string &constraints, bool hasSideEffects)
  : Value(PointerType::get(Ty), Value::InlineAsmVal), AsmString(asmString),
    Constraints(constraints), HasSideEffects(hasSideEffects) {

  // Do various checks on the constraint string and type.
  assert(Verify(Ty, constraints) && "Function type not legal for constraints!");
}

const FunctionType *InlineAsm::getFunctionType() const {
  return cast<FunctionType>(getType()->getElementType());
}

/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
/// fields in this structure.  If the constraint string is not understood,
/// return true, otherwise return false.
bool InlineAsm::ConstraintInfo::Parse(const std::string &Str,
                     std::vector<InlineAsm::ConstraintInfo> &ConstraintsSoFar) {
  std::string::const_iterator I = Str.begin(), E = Str.end();

  // Initialize
  Type = isInput;
  isEarlyClobber = false;
  isIndirectOutput = false;
  hasMatchingInput = false;
  isCommutative = false;

  // Parse the prefix.
  if (*I == '~') {
    Type = isClobber;
    ++I;
  } else if (*I == '=') {
    ++I;
    Type = isOutput;
    if (I != E && *I == '=') {
      isIndirectOutput = true;
      ++I;
    }
  }

  if (I == E) return true;  // Just a prefix, like "==" or "~".

  // Parse the modifiers.
  bool DoneWithModifiers = false;
  while (!DoneWithModifiers) {
    switch (*I) {
    default:
      DoneWithModifiers = true;
      break;
    case '&':     // Early clobber.
      if (Type != isOutput ||      // Cannot early clobber anything but output.
          isEarlyClobber)          // Reject &&&&&&
        return true;
      isEarlyClobber = true;
      break;
    case '%':     // Commutative.
      if (Type == isClobber ||     // Cannot commute clobbers.
          isCommutative)           // Reject %%%%%
        return true;
      isCommutative = true;
      break;
    case '#':     // Comment.
    case '*':     // Register preferencing.
      return true;     // Not supported.
    }

    if (!DoneWithModifiers) {
      ++I;
      if (I == E) return true;   // Just prefixes and modifiers!
    }
  }

  // Parse the various constraints.
  while (I != E) {
    if (*I == '{') {   // Physical register reference.
      // Find the end of the register name.
      std::string::const_iterator ConstraintEnd = std::find(I+1, E, '}');
      if (ConstraintEnd == E) return true;  // "{foo"
      Codes.push_back(std::string(I, ConstraintEnd+1));
      I = ConstraintEnd+1;
    } else if (isdigit(*I)) {     // Matching Constraint
      // Maximal munch numbers.
      std::string::const_iterator NumStart = I;
      while (I != E && isdigit(*I))
        ++I;
      Codes.push_back(std::string(NumStart, I));
      unsigned N = atoi(Codes.back().c_str());
      // Check that this is a valid matching constraint!
      if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||
          Type != isInput)
        return true;  // Invalid constraint number.

      // Note that operand #n has a matching input.
      ConstraintsSoFar[N].hasMatchingInput = true;
    } else {
      // Single letter constraint.
      Codes.push_back(std::string(I, I+1));
      ++I;
    }
  }

  return false;
}

std::vector<InlineAsm::ConstraintInfo>
InlineAsm::ParseConstraints(const std::string &Constraints) {
  std::vector<ConstraintInfo> Result;

  // Scan the constraints string.
  for (std::string::const_iterator I = Constraints.begin(),
       E = Constraints.end(); I != E; ) {
    ConstraintInfo Info;

    // Find the end of this constraint.
    std::string::const_iterator ConstraintEnd = std::find(I, E, ',');

    if (ConstraintEnd == I ||  // Empty constraint like ",,"
        Info.Parse(std::string(I, ConstraintEnd), Result)) {
      Result.clear();          // Erroneous constraint?
      break;
    }

    Result.push_back(Info);

    // ConstraintEnd may be either the next comma or the end of the string.  In
    // the former case, we skip the comma.
    I = ConstraintEnd;
    if (I != E) {
      ++I;
      if (I == E) { Result.clear(); break; }    // don't allow "xyz,"
    }
  }

  return Result;
}

/// Verify - Verify that the specified constraint string is reasonable for the
/// specified function type, and otherwise validate the constraint string.
bool InlineAsm::Verify(const FunctionType *Ty, const std::string &ConstStr) {
  if (Ty->isVarArg()) return false;

  std::vector<ConstraintInfo> Constraints = ParseConstraints(ConstStr);

  // Error parsing constraints.
  if (Constraints.empty() && !ConstStr.empty()) return false;

  unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;

  for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
    switch (Constraints[i].Type) {
    case InlineAsm::isOutput:
      if (!Constraints[i].isIndirectOutput) {
        if (NumInputs || NumClobbers) return false;  // outputs come first.
        ++NumOutputs;
        break;
      }
      // FALLTHROUGH for IndirectOutputs.
    case InlineAsm::isInput:
      if (NumClobbers) return false;               // inputs before clobbers.
      ++NumInputs;
      break;
    case InlineAsm::isClobber:
      ++NumClobbers;
      break;
    }
  }

  if (NumOutputs > 1) return false;  // Only one result allowed so far.

  if ((Ty->getReturnType() != Type::VoidTy) != NumOutputs)
    return false;   // NumOutputs = 1 iff has a result type.

  if (Ty->getNumParams() != NumInputs) return false;
  return true;
}
<|endoftext|>