diff --git a/compiler/qsc/src/codegen.rs b/compiler/qsc/src/codegen.rs index 253b6f21ab..54ad8388c7 100644 --- a/compiler/qsc/src/codegen.rs +++ b/compiler/qsc/src/codegen.rs @@ -10,7 +10,7 @@ pub mod qsharp { } pub mod qir { - use qsc_codegen::qir::fir_to_qir; + use qsc_codegen::qir::{fir_to_qir, fir_to_rir}; use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags}; use qsc_frontend::{ @@ -87,6 +87,39 @@ pub mod qir { ))] }) } + + pub fn get_rir( + sources: SourceMap, + language_features: LanguageFeatures, + capabilities: TargetCapabilityFlags, + mut package_store: PackageStore, + dependencies: &Dependencies, + ) -> Result, Vec> { + let (package_id, fir_store, entry, compute_properties) = compile_to_fir( + sources, + language_features, + capabilities, + &mut package_store, + dependencies, + )?; + + let (raw, ssa) = fir_to_rir(&fir_store, capabilities, Some(compute_properties), &entry) + .map_err(|e| { + let source_package_id = match e.span() { + Some(span) => span.package, + None => package_id, + }; + let source_package = package_store + .get(source_package_id) + .expect("package should be in store"); + vec![Error::PartialEvaluation(WithSource::from_map( + &source_package.sources, + e, + ))] + })?; + Ok(vec![raw.to_string(), ssa.to_string()]) + } + pub fn get_qir( sources: SourceMap, language_features: LanguageFeatures, @@ -94,26 +127,60 @@ pub mod qir { mut package_store: PackageStore, dependencies: &Dependencies, ) -> Result> { + let (package_id, fir_store, entry, compute_properties) = compile_to_fir( + sources, + language_features, + capabilities, + &mut package_store, + dependencies, + )?; + + fir_to_qir(&fir_store, capabilities, Some(compute_properties), &entry).map_err(|e| { + let source_package_id = match e.span() { + Some(span) => span.package, + None => package_id, + }; + let source_package = package_store + .get(source_package_id) + .expect("package should be in store"); + vec![Error::PartialEvaluation(WithSource::from_map( + &source_package.sources, + e, + ))] + }) + } + + fn compile_to_fir( + sources: SourceMap, + language_features: LanguageFeatures, + capabilities: TargetCapabilityFlags, + package_store: &mut PackageStore, + dependencies: &[(qsc_hir::hir::PackageId, Option>)], + ) -> Result< + ( + qsc_hir::hir::PackageId, + qsc_fir::fir::PackageStore, + ProgramEntry, + qsc_rca::PackageStoreComputeProperties, + ), + Vec, + > { if capabilities == TargetCapabilityFlags::all() { return Err(vec![Error::UnsupportedRuntimeCapabilities]); } - let (unit, errors) = crate::compile::compile( - &package_store, + package_store, dependencies, sources, PackageType::Exe, capabilities, language_features, ); - - // Ensure it compiles before trying to add it to the store. if !errors.is_empty() { return Err(errors.iter().map(|e| Error::Compile(e.clone())).collect()); } - let package_id = package_store.insert(unit); - let (fir_store, fir_package_id) = qsc_passes::lower_hir_to_fir(&package_store, package_id); + let (fir_store, fir_package_id) = qsc_passes::lower_hir_to_fir(package_store, package_id); let package = fir_store.get(fir_package_id); let entry = ProgramEntry { exec_graph: package.entry_exec_graph.clone(), @@ -125,7 +192,6 @@ pub mod qir { ) .into(), }; - let compute_properties = PassContext::run_fir_passes_on_fir( &fir_store, fir_package_id, @@ -140,19 +206,6 @@ pub mod qir { .map(|e| Error::Pass(WithSource::from_map(&source_package.sources, e.clone()))) .collect::>() })?; - - fir_to_qir(&fir_store, capabilities, Some(compute_properties), &entry).map_err(|e| { - let source_package_id = match e.span() { - Some(span) => span.package, - None => package_id, - }; - let source_package = package_store - .get(source_package_id) - .expect("package should be in store"); - vec![Error::PartialEvaluation(WithSource::from_map( - &source_package.sources, - e, - ))] - }) + Ok((package_id, fir_store, entry, compute_properties)) } } diff --git a/compiler/qsc_codegen/src/qir.rs b/compiler/qsc_codegen/src/qir.rs index e80fcc06e0..96448e897c 100644 --- a/compiler/qsc_codegen/src/qir.rs +++ b/compiler/qsc_codegen/src/qir.rs @@ -13,7 +13,7 @@ use qsc_partial_eval::{partially_evaluate, ProgramEntry}; use qsc_rca::PackageStoreComputeProperties; use qsc_rir::{ passes::check_and_transform, - rir::{self, ConditionCode}, + rir::{self, ConditionCode, Program}, utils::get_all_block_successors, }; @@ -37,6 +37,18 @@ pub fn hir_to_qir( fir_to_qir(&fir_store, capabilities, compute_properties, entry) } +pub fn fir_to_rir( + fir_store: &qsc_fir::fir::PackageStore, + capabilities: TargetCapabilityFlags, + compute_properties: Option, + entry: &ProgramEntry, +) -> Result<(Program, Program), qsc_partial_eval::Error> { + let mut program = get_rir_from_compilation(fir_store, compute_properties, entry, capabilities)?; + let orig = program.clone(); + check_and_transform(&mut program); + Ok((orig, program)) +} + pub fn fir_to_qir( fir_store: &qsc_fir::fir::PackageStore, capabilities: TargetCapabilityFlags, diff --git a/npm/qsharp/src/compiler/compiler.ts b/npm/qsharp/src/compiler/compiler.ts index 67345326c3..ce9c0aa49e 100644 --- a/npm/qsharp/src/compiler/compiler.ts +++ b/npm/qsharp/src/compiler/compiler.ts @@ -45,6 +45,8 @@ export interface ICompiler { profile?: TargetProfile, ): Promise; + getRir(program: ProgramConfig): Promise; + run( program: ProgramConfig, expr: string, @@ -162,6 +164,14 @@ export class Compiler implements ICompiler { ); } + async getRir(program: ProgramConfig): Promise { + const config = toWasmProgramConfig( + program, + program.profile || "adaptive_ri", + ); + return this.wasm.get_rir(config); + } + async run( program: ProgramConfig, expr: string, @@ -319,6 +329,7 @@ export const compilerProtocol: ServiceProtocol = { checkCode: "request", getAst: "request", getHir: "request", + getRir: "request", getQir: "request", getEstimates: "request", getCircuit: "request", diff --git a/npm/qsharp/ux/qsharp-ux.css b/npm/qsharp/ux/qsharp-ux.css index 67c4e04610..7adc5961fb 100644 --- a/npm/qsharp/ux/qsharp-ux.css +++ b/npm/qsharp/ux/qsharp-ux.css @@ -283,6 +283,14 @@ html { white-space: pre; } +.rir-output { + height: 40vh; + min-height: 400px; + width: 100%; + resize: none; + white-space: pre; +} + .qir-output { height: 40vh; min-height: 400px; diff --git a/playground/src/editor.tsx b/playground/src/editor.tsx index d8929e6126..57c17c5f16 100644 --- a/playground/src/editor.tsx +++ b/playground/src/editor.tsx @@ -90,6 +90,7 @@ export function Editor(props: { profile: TargetProfile; setAst: (ast: string) => void; setHir: (hir: string) => void; + setRir: (rir: string[]) => void; setQir: (qir: string) => void; activeTab: ActiveTab; languageService: ILanguageServiceWorker; @@ -159,7 +160,7 @@ export function Editor(props: { ); } const codeGenTimeout = 1000; // ms - if (props.activeTab === "qir-tab") { + if (props.activeTab === "qir-tab" || props.activeTab === "rir-tab") { let timedOut = false; const compiler = props.compiler_worker_factory(); const compilerTimeout = setTimeout(() => { @@ -168,14 +169,28 @@ export function Editor(props: { compiler.terminate(); }, codeGenTimeout); try { - const qir = await compiler.getQir(config); - clearTimeout(compilerTimeout); - props.setQir(qir); + if (props.activeTab === "rir-tab") { + const ir = await compiler.getRir(config); + clearTimeout(compilerTimeout); + props.setRir(ir); + } else { + const ir = await compiler.getQir(config); + clearTimeout(compilerTimeout); + props.setQir(ir); + } } catch (e: any) { if (timedOut) { - props.setQir("timed out"); + if (props.activeTab === "rir-tab") { + props.setRir(["timed out", "timed out"]); + } else { + props.setQir("timed out"); + } } else { - props.setQir(e.toString()); + if (props.activeTab === "rir-tab") { + props.setRir([e.toString(), e.toString()]); + } else { + props.setQir(e.toString()); + } } } finally { compiler.terminate(); diff --git a/playground/src/kata.tsx b/playground/src/kata.tsx index 3aa5650ea5..a858d7afb8 100644 --- a/playground/src/kata.tsx +++ b/playground/src/kata.tsx @@ -113,6 +113,7 @@ function LessonElem(props: Props & { section: KataSection }) { profile={getProfile()} setAst={() => ({})} setHir={() => ({})} + setRir={() => ({})} setQir={() => ({})} activeTab="results-tab" languageService={props.languageService} @@ -124,6 +125,7 @@ function LessonElem(props: Props & { section: KataSection }) { onShotError={(diag?: VSDiagnostic) => setShotError(diag)} ast="" hir="" + rir={["", ""]} qir="" activeTab="results-tab" setActiveTab={() => undefined} @@ -176,6 +178,7 @@ function ExerciseElem(props: Props & { section: KataSection }) { profile={getProfile()} setAst={() => ({})} setHir={() => ({})} + setRir={() => ({})} setQir={() => ({})} activeTab="results-tab" languageService={props.languageService} @@ -187,6 +190,7 @@ function ExerciseElem(props: Props & { section: KataSection }) { onShotError={(diag?: VSDiagnostic) => setShotError(diag)} ast="" hir="" + rir={["", ""]} qir="" activeTab="results-tab" setActiveTab={() => undefined} diff --git a/playground/src/main.tsx b/playground/src/main.tsx index 3d945f18ff..09cb330f1b 100644 --- a/playground/src/main.tsx +++ b/playground/src/main.tsx @@ -56,7 +56,12 @@ md.use((mk as any).default, { }); // Not sure why it's not using the default export automatically :-/ setRenderer((input: string) => md.render(input)); -export type ActiveTab = "results-tab" | "ast-tab" | "hir-tab" | "qir-tab"; +export type ActiveTab = + | "results-tab" + | "ast-tab" + | "hir-tab" + | "rir-tab" + | "qir-tab"; const basePath = (window as any).qscBasePath || ""; const monacoPath = basePath + "libs/monaco/vs"; @@ -104,6 +109,7 @@ function App(props: { katas: Kata[]; linkedCode?: string }) { const [ast, setAst] = useState(""); const [hir, setHir] = useState(""); + const [rir, setRir] = useState(["", ""]); const [qir, setQir] = useState(""); const [activeTab, setActiveTab] = useState("results-tab"); @@ -177,6 +183,7 @@ function App(props: { katas: Kata[]; linkedCode?: string }) { profile={getProfile()} setAst={setAst} setHir={setHir} + setRir={setRir} setQir={setQir} activeTab={activeTab} languageService={languageService} @@ -187,6 +194,7 @@ function App(props: { katas: Kata[]; linkedCode?: string }) { onShotError={(diag?: VSDiagnostic) => setShotError(diag)} ast={ast} hir={hir} + rir={rir} qir={qir} activeTab={activeTab} setActiveTab={setActiveTab} diff --git a/playground/src/tabs.tsx b/playground/src/tabs.tsx index cab4c1e3ac..f6f1c519fe 100644 --- a/playground/src/tabs.tsx +++ b/playground/src/tabs.tsx @@ -9,6 +9,7 @@ const tabArray: Array<[ActiveTab, string]> = [ ["results-tab", "RESULTS"], ["ast-tab", "AST"], ["hir-tab", "HIR"], + ["rir-tab", "RIR"], ["qir-tab", "QIR"], ]; @@ -28,6 +29,21 @@ function HirTab(props: { hir: string; activeTab: ActiveTab }) { ) : null; } +function RirTab(props: { rir: string[]; activeTab: ActiveTab }) { + const raw = props.rir[0]; + const ssa = props.rir[1]; + return props.activeTab === "rir-tab" ? ( +
+ + +
+ ) : null; +} + function QirTab(props: { qir: string; activeTab: ActiveTab }) { return props.activeTab === "qir-tab" ? (