Commit 6a935cc9 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

syncing up work on Improved Scaffold Compiler

parent 0c63ae2a
from mccaskey/base-fedora-gcc6
run dnf -y install spdlog llvm-devel libstdc++-static clang-devel \
run dnf -y install spdlog libstdc++-static \
https://github.com/ORNL-QCI/ScaffCC/releases/download/v2.0/scaffold-2.0-1.fc25.x86_64.rpm \
&& git clone --recursive https://github.com/ORNL-QCI/xacc \
&& rm -rf /projects/xacc/tpls/fire/.git \
......
......@@ -37,7 +37,7 @@ file (GLOB SRC *.cpp)
set(CMAKE_CXX_FLAGS "-D_DEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -O3 -w -fomit-frame-pointer -fvisibility-inlines-hidden -fPIC -Woverloaded-virtual -Wcast-qual")
set_source_files_properties(MyASTConsumer.cpp PROPERTIES COMPILE_FLAGS -fno-rtti)
set_source_files_properties(ScaffoldASTConsumer.cpp PROPERTIES COMPILE_FLAGS -fno-rtti)
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate)
include_directories(/usr/local/scaffold/include)
......
/***********************************************************************************
* Copyright (c) 2016, UT-Battelle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the xacc nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* Initial API and implementation - Alex McCaskey
*
**********************************************************************************/
#ifndef QUANTUM_GATE_SCAFFOLD_IMPROVEDSCAFFCCAPI_HPP_
#define QUANTUM_GATE_SCAFFOLD_IMPROVEDSCAFFCCAPI_HPP_
#include <cstdlib>
#include "XACCError.hpp"
#include <iostream>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Support/IRReader.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Type.h"
#include "llvm/Support/Host.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "MyASTConsumer.hpp"
using namespace clang;
namespace scaffold {
/**
* The ScaffCCAPI is a simple utility class that provides
* methods for interacting with an installed Scaffold compiler.
* It's main function is to take user-specified XACC kernel
* source code and compile it to flatted QASM using the
* Scaffold compiler.
*/
class ImprovedScaffCCAPI {
protected:
const std::string kernelSource;
llvm::Module * mod;
public:
ImprovedScaffCCAPI(const std::string& kernelStr) :
kernelSource(kernelStr) {
// Create a temporary scaffold soruce file
std::ofstream tempSrcFile(".tmpSrcFile.scaffold");
tempSrcFile << kernelSource;
tempSrcFile.close();
// Execute the scaffold compiler
std::system(
"/usr/local/scaffold/build/Release+Asserts/bin/clang "
"-S -c -emit-llvm .tmpSrcFile.scaffold -o out.ll");
using namespace llvm;
SMDiagnostic err;
LLVMContext &ctx = getGlobalContext();
mod = ParseIRFile("out.ll", err, ctx);
if (!mod) {
XACCError("LLVM Module was null");
}
}
/**
* Return a string containing flatted QASM representing
* the provided high level Scaffold source code. This method
* assumes that the Scaffold compiler is on the current user's
* PATH and is called scaffcc.
*
* @param source The scaffold kernel source code.
* @return flattenedQASM The QASM representation of the given source.
*/
std::string getFlatQASMFromSource(const std::string& source) {
// Check if scaffcc exists on the PATH
if (std::system("which scaffcc > /dev/null 2>&1") == 0) {
// Create a temporary scaffold soruce file
std::ofstream tempSrcFile(".tmpSrcFile.scaffold");
tempSrcFile << source;
tempSrcFile.close();
// Execute the scaffold compiler
std::system("scaffcc -fRp .tmpSrcFile.scaffold &> /dev/null");
// Remove the temporary source file, we don't need it anymore
std::remove(".tmpSrcFile.scaffold");
// Read in the generated QASM
std::ifstream flatQASM(".tmpSrcFile.qasmf");
std::string qasm((std::istreambuf_iterator<char>(flatQASM)),
std::istreambuf_iterator<char>());
// Remove created scaffold files.
std::remove(".tmpSrcFile.qasmf");
std::remove(".tmpSrcFile.qasmh");
// Return the QASM
return qasm;
} else {
XACCError(
"Cannot find scaffold compiler. Make sure scaffcc is in PATH and executable.");
}
}
std::vector<std::string> getFunctionNames() {
std::vector<std::string> fNames;
for (auto i = mod->getFunctionList().begin(), j = mod->getFunctionList().end(); i!=j; ++i) {
auto fName = i->getName().str();
if (!(boost::contains(fName, "llvm")
&& boost::contains(fName, "i16")))
fNames.push_back(i->getName().str());
}
return fNames;
}
void checkIfStmts() {
CompilerInstance CI;
// DiagnosticOptions diagnosticOptions;
// TextDiagnosticPrinter *pTextDiagnosticPrinter =
// new TextDiagnosticPrinter(
// llvm::outs(), diagnosticOptions, true);
CI.createDiagnostics(0, 0);//NULL, pTextDiagnosticPrinter);
TargetOptions targetOptions;
targetOptions.Triple = llvm::sys::getDefaultTargetTriple();
TargetInfo *pTargetInfo = TargetInfo::CreateTargetInfo(
CI.getDiagnostics(), targetOptions);
CI.setTarget(pTargetInfo);
CI.createFileManager();
CI.createSourceManager(CI.getFileManager());
CI.createPreprocessor();
CI.getPreprocessorOpts().UsePredefines = false;
auto astConsumer = new MyASTConsumer();
CI.setASTConsumer(astConsumer);
CI.createASTContext();
// CI.createSema(clang::TU_Complete, NULL);
const FileEntry *pFile = CI.getFileManager().getFile(".tmpSrcFile.scaffold");
CI.getSourceManager().createMainFileID(pFile);
CI.getASTContext().BuiltinInfo.InitializeBuiltins(
CI.getPreprocessor().getIdentifierTable(), CI.getLangOpts());
// CI.getDiagnosticClient().BeginSourceFile(
// CI.getLangOpts(), &(CI.getPreprocessor()));
// clang::ParseAST(CI.getSema());
// CI.getDiagnosticClient().EndSourceFile();
clang::ParseAST(CI.getPreprocessor(), astConsumer, CI.getASTContext());
}
};
}
#endif
......@@ -32,41 +32,68 @@
#include "ImprovedScaffold.hpp"
#include "GateQIR.hpp"
using namespace clang;
namespace xacc {
namespace quantum {
void ImprovedScaffoldCompiler::modifySource() {
// Here we assume we've been given just
// the body of the quantum code, as part
// of an xacc __qpu__ kernel function.
// First off, replace __qpu__ with 'module '
kernelSource.erase(kernelSource.find("__qpu__"), 7);
kernelSource = std::string("module ") + kernelSource;
// std::cout << "\n" << kernelSource << "\n";
ImprovedScaffoldCompiler::ImprovedScaffoldCompiler() {
CI = std::make_shared<CompilerInstance>();
CI->createDiagnostics(0, 0);
TargetOptions targetOptions;
targetOptions.Triple = llvm::sys::getDefaultTargetTriple();
TargetInfo *pTargetInfo = TargetInfo::CreateTargetInfo(CI->getDiagnostics(),
targetOptions);
CI->setTarget(pTargetInfo);
CI->createFileManager();
CI->createSourceManager(CI->getFileManager());
CI->createPreprocessor();
CI->getPreprocessorOpts().UsePredefines = false;
CI->createASTContext();
}
std::shared_ptr<IR> ImprovedScaffoldCompiler::compile(const std::string& src,
std::shared_ptr<Accelerator> acc) {
return std::make_shared<GateQIR>();
}
std::shared_ptr<IR> ImprovedScaffoldCompiler::compile(const std::string& src) {
return std::make_shared<GateQIR>();
}
kernelSource = src;
if (boost::contains(kernelSource, "__qpu__")) {
kernelSource.erase(kernelSource.find("__qpu__"), 7);
kernelSource = std::string("module") + kernelSource;
std::cout << "\n" << kernelSource << "\n";
}
} // end namespace quantum
// Create a temporary scaffold source file
std::ofstream tempSrcFile(".tmpSrcFile.scaffold");
tempSrcFile << kernelSource;
tempSrcFile.close();
} // end namespace xacc
//
const FileEntry *pFile = CI->getFileManager().getFile(
".tmpSrcFile.scaffold");
CI->getSourceManager().createMainFileID(pFile);
CI->getASTContext().BuiltinInfo.InitializeBuiltins(
CI->getPreprocessor().getIdentifierTable(), CI->getLangOpts());
// Register the ScaffoldCompiler with the CompilerRegistry.
static xacc::RegisterCompiler<xacc::quantum::ImprovedScaffoldCompiler> X("improvedscaffold");
consumer = std::make_shared<scaffold::ScaffoldASTConsumer>();//&CI->getASTContext());
clang::ParseAST(CI->getPreprocessor(), consumer.get(), CI->getASTContext());
auto qirFunction = consumer->getFunction();
auto qir = std::make_shared<GateQIR>();
qir->addQuantumKernel(qirFunction);
return qir;
}
}
}
static xacc::RegisterCompiler<xacc::quantum::ImprovedScaffoldCompiler> X(
"improvedscaffold");
......@@ -35,7 +35,8 @@
#include "XACCError.hpp"
#include <boost/algorithm/string.hpp>
#include "Accelerator.hpp"
#include "ImprovedScaffCCAPI.hpp"
#include "ScaffoldASTConsumer.hpp"
namespace xacc {
......@@ -47,10 +48,12 @@ namespace quantum {
* to handle generation of quantum assembly language (or QASM)
* using an installed Scaffold compiler.
*/
class ImprovedScaffoldCompiler : public xacc::Compiler {
class ImprovedScaffoldCompiler: public xacc::Compiler {
public:
ImprovedScaffoldCompiler();
/**
* Execute the Scaffold compiler to generate an
* XACC intermediate representation instance.
......@@ -76,12 +79,11 @@ public:
protected:
/**
* This method is intended to modify the incoming
* source code to be compiled to be amenable to the
* Scaffold compiler.
*/
virtual void modifySource();
std::string cbitVarName;
std::string qbitVarName;
std::shared_ptr<clang::CompilerInstance> CI;
std::shared_ptr<scaffold::ScaffoldASTConsumer> consumer;
/**
* Reference to potential conditional code
......
/*
* MyASTConsumer.cpp
*
* Created on: Apr 19, 2017
* Author: aqw
*/
#include "MyASTConsumer.hpp"
MyASTConsumer::MyASTConsumer() :
Visitor(std::make_shared<MyASTVisitor>()) {
}
bool MyASTConsumer::HandleTopLevelDecl(DeclGroupRef DR) {
for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
// Traverse the declaration using our AST visitor.
Visitor->TraverseDecl(*b);
}
return true;
}
#include "ScaffoldASTConsumer.hpp"
#include <iostream>
#include <boost/algorithm/string.hpp>
#include "ParameterizedGateInstruction.hpp"
namespace scaffold {
bool ScaffoldASTConsumer::HandleTopLevelDecl(DeclGroupRef DR) {
for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
// Traverse the declaration using our AST visitor.
TraverseDecl(*b);
}
return true;
}
bool ScaffoldASTConsumer::VisitDecl(Decl *d) {
if (isa<VarDecl>(d)) {
auto varDecl = cast<VarDecl>(d);
auto varType = varDecl->getType().getAsString();
if (boost::contains(varType, "cbit")) {
cbitVarName = varDecl->getDeclName().getAsString();
std::cout << "Found " << cbitVarName << "\n";
} else if (boost::contains(varType, "qbit")) {
qbitVarName = varDecl->getDeclName().getAsString();
std::cout << "Found " << qbitVarName << "\n";
}
} else if (isa<FunctionDecl>(d)) {
auto c = cast<FunctionDecl>(d);
function = std::make_shared<xacc::quantum::GateFunction>(0,
c->getDeclName().getAsString());
}
return true;
}
bool ScaffoldASTConsumer::VisitStmt(Stmt *s) {
if (isa<IfStmt>(s)) {
auto ifStmt = cast<IfStmt>(s);
clang::LangOptions lo;
clang::PrintingPolicy policy(lo);
std::string ifStr;
llvm::raw_string_ostream ifS(ifStr);
ifStmt->printPretty(ifS, nullptr, policy);
std::cout << "HELLO IF:\n" << ifS.str() << "\n";
if (const auto binOp = llvm::dyn_cast<BinaryOperator>(
ifStmt->getCond())) {
if (binOp->getOpcode() == BO_EQ) {
// We have an equality check...
auto LHS = binOp->getLHS();
std::string str;
llvm::raw_string_ostream s(str);
LHS->printPretty(s, nullptr, policy);
if (boost::contains(s.str(), cbitVarName)) {
auto RHS = binOp->getRHS();
std::string rhsstr;
llvm::raw_string_ostream rhss(rhsstr);
RHS->printPretty(rhss, nullptr, policy);
auto thenCode = ifStmt->getThen();
std::string thenStr;
llvm::raw_string_ostream thenS(thenStr);
thenCode->printPretty(thenS, nullptr, policy);
auto then = thenS.str();
std::cout << "ThenStmt:\n" << then << "\n";
then.erase(std::remove(then.begin(), then.end(), '\t'),
then.end());
boost::replace_all(then, "{\n", "");
boost::replace_all(then, "}\n", "");
boost::replace_all(then, " ", "");
boost::trim(then);
}
}
}
}
return true;
}
bool ScaffoldASTConsumer::VisitCallExpr(CallExpr* c) {
clang::LangOptions lo;
clang::PrintingPolicy policy(lo);
auto q = c->getType();
auto t = q.getTypePtrOrNull();
if (t != NULL) {
bool isParameterizedInst = false;
auto fd = c->getDirectCallee();
std::cout << "HOWDY: " << fd->getNameInfo().getAsString() << "\n";
auto gateName = fd->getNameInfo().getAsString();
std::vector<int> qubits;
std::vector<double> params;
for (auto i = c->arg_begin(); i != c->arg_end(); ++i) {
std::string arg;
llvm::raw_string_ostream argstream(arg);
i->printPretty(argstream, nullptr, policy);
auto argStr = argstream.str();
std::cout << "Arg: " << argstream.str() << "\n";
if (boost::contains(argStr, qbitVarName)) {
boost::replace_all(argStr, qbitVarName, "");
boost::replace_all(argStr, "[", "");
boost::replace_all(argStr, "]", "");
qubits.push_back(std::stoi(argStr));
} else {
// This is a gate parameter!!!
isParameterizedInst = true;
params.push_back(std::stod(argStr));
}
}
std::shared_ptr<xacc::quantum::GateInstruction> inst;
if (isParameterizedInst) {
if (params.size() == 1) {
inst = xacc::quantum::ParameterizedGateInstructionRegistry<
double>::instance()->create(gateName, currentInstId,
currentInstLayer, qubits, params[0]);
} else if (params.size() == 2) {
inst = xacc::quantum::ParameterizedGateInstructionRegistry<
double, double>::instance()->create(gateName,
currentInstId, currentInstLayer, qubits, params[0],
params[1]);
} else {
XACCError(
"Can only handle 1 and 2 parameter gates... and only doubles... for now.");
}
std::cout << "CREATED A " << gateName << " gate\n";
} else if (gateName != "MeasZ") {
inst = xacc::quantum::GateInstructionRegistry::instance()->create(
gateName, currentInstId, currentInstLayer, qubits);
std::cout << "CREATED A " << gateName << " gate\n";
}
if (gateName != "MeasZ") function->addInstruction(inst);
}
return true;
}
bool ScaffoldASTConsumer::VisitBinaryOperator(BinaryOperator * b) {
clang::LangOptions lo;
clang::PrintingPolicy policy(lo);
if (b->isAssignmentOp()) {
auto rhs = b->getRHS();
std::string rhsstr;
llvm::raw_string_ostream rhss(rhsstr);
rhs->printPretty(rhss, nullptr, policy);
auto rhsString = rhss.str();
std::cout << "HELLO BINOP: " << rhsString << "\n";
if (boost::contains(rhsString, "MeasZ")) {
auto lhs = b->getLHS();
std::string lhsstr;
llvm::raw_string_ostream lhss(lhsstr);
lhs->printPretty(lhss, nullptr, policy);
auto lhsString = lhss.str();
std::cout << "HELLO BINOP LHS: " << lhsString << "\n";
boost::replace_all(lhsString, cbitVarName, "");
boost::replace_all(lhsString, "[","");
boost::replace_all(lhsString, "]", "");
boost::replace_all(rhsString, "MeasZ", "");
boost::replace_all(rhsString, "(","");
boost::replace_all(rhsString, ")", "");
boost::replace_all(rhsString, qbitVarName, "");
boost::replace_all(rhsString, "[","");
boost::replace_all(rhsString, "]", "");
// lhsString now just contains the classical index bit
auto inst =
xacc::quantum::ParameterizedGateInstructionRegistry<int>::instance()->create(
"Measure", currentInstId, currentInstLayer,
std::vector<int> { std::stoi(rhsString) },
std::stoi(lhsString));
function->addInstruction(inst);
}
}
return true;
}
}
......@@ -5,8 +5,18 @@
* Author: aqw
*/
#ifndef QUANTUM_GATE_COMPILERS_IMPROVEDSCAFFOLD_MYASTCONSUMER_HPP_
#define QUANTUM_GATE_COMPILERS_IMPROVEDSCAFFOLD_MYASTCONSUMER_HPP_
#ifndef QUANTUM_GATE_COMPILERS_IMPROVEDSCAFFOLD_SCAFFOLDASTCONSUMER_HPP_
#define QUANTUM_GATE_COMPILERS_IMPROVEDSCAFFOLD_SCAFFOLDASTCONSUMER_HPP_
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Support/IRReader.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Type.h"
#include "llvm/Support/Host.h"