aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--patio-to-cranelift/src/codegen/mod.rs28
-rw-r--r--patio-to-cranelift/src/lib.rs8
-rw-r--r--patio-to-cranelift/src/main.rs8
-rw-r--r--src/main/java/org/shedlang/compiler/backends/cranelift/CraneliftBackend.java136
-rw-r--r--src/test/java/org/shedlang/compiler/backends/cranelift/CraneliftAmd64ExampleTests.java34
5 files changed, 204 insertions, 10 deletions
diff --git a/patio-to-cranelift/src/codegen/mod.rs b/patio-to-cranelift/src/codegen/mod.rs
index 85fbae6c..7fad42f5 100644
--- a/patio-to-cranelift/src/codegen/mod.rs
+++ b/patio-to-cranelift/src/codegen/mod.rs
@@ -32,6 +32,7 @@ mod values;
pub(crate) fn compile_compilation_unit(
compilation_unit: PatioCompilationUnit,
+ main: Option<&str>,
source_path: &Path,
target_triple: target_lexicon::Triple,
) -> Result<Vec<u8>, CompileError> {
@@ -45,6 +46,33 @@ pub(crate) fn compile_compilation_unit(
define_compilation_unit_element(&element, &mut context);
}
+ if let Some(main) = main {
+ let mut main_signature = new_cranelift_signature();
+ main_signature
+ .returns
+ .push(cranelift_codegen::ir::AbiParam::new(
+ cranelift_codegen::ir::types::I32,
+ ));
+
+ context.declare_function("main", cranelift_module::Linkage::Export, &main_signature);
+ context.enter_function("main", main_signature, |function_context| {
+ let func_ref = function_context.func_id(main);
+ function_context.function_builder.ins().call(func_ref, &[]);
+ // TODO: we ignore the return value and just return 0, which is fine
+ // in practice since we use exit() for non-zero exit codes. However,
+ // we should clarify this behaviour in shid-to-patio, and other
+ // patio backends.
+ let exit_code = function_context
+ .function_builder
+ .ins()
+ .iconst(cranelift_codegen::ir::types::I32, 0);
+ function_context
+ .function_builder
+ .ins()
+ .return_(&[exit_code]);
+ });
+ }
+
let object = context.into_object();
object.emit().map_err(CompileError::ObjectEmitFailed)
}
diff --git a/patio-to-cranelift/src/lib.rs b/patio-to-cranelift/src/lib.rs
index 22afabba..80d22840 100644
--- a/patio-to-cranelift/src/lib.rs
+++ b/patio-to-cranelift/src/lib.rs
@@ -14,7 +14,11 @@ mod codegen;
mod errors;
mod patio;
-pub fn compile(source_path: &Path, target_str: &str) -> Result<(), CompileError> {
+pub fn compile(
+ source_path: &Path,
+ target_str: &str,
+ main: Option<&str>,
+) -> Result<(), CompileError> {
let source_bytes = std::fs::read(source_path).map_err(CompileError::ReadSourceBytes)?;
let compilation_unit: PatioCompilationUnit =
@@ -26,7 +30,7 @@ pub fn compile(source_path: &Path, target_str: &str) -> Result<(), CompileError>
target_lexicon::Triple::from_str(target_str).map_err(CompileError::ParseTargetTriple)?;
let object_bytes =
- codegen::compile_compilation_unit(compilation_unit, source_path, target_triple)?;
+ codegen::compile_compilation_unit(compilation_unit, main, source_path, target_triple)?;
let destination_path = source_path.with_extension("o");
std::fs::write(destination_path, object_bytes).map_err(CompileError::WriteObjectFile)?;
diff --git a/patio-to-cranelift/src/main.rs b/patio-to-cranelift/src/main.rs
index 77409d1f..e000dbd2 100644
--- a/patio-to-cranelift/src/main.rs
+++ b/patio-to-cranelift/src/main.rs
@@ -11,12 +11,18 @@ struct Args {
/// The LLVM triple to target.
#[arg(long)]
target: String,
+
+ /// The name of the main function. If set, this will add a C-style `main`
+ /// function that calls the given main function, and converts the return
+ /// value into an int32.
+ #[arg(long)]
+ main: Option<String>,
}
fn main() {
let args = Args::parse();
for source_path in args.source_paths {
- patio_to_cranelift::compile(&source_path, &args.target).unwrap();
+ patio_to_cranelift::compile(&source_path, &args.target, args.main.as_deref()).unwrap();
}
}
diff --git a/src/main/java/org/shedlang/compiler/backends/cranelift/CraneliftBackend.java b/src/main/java/org/shedlang/compiler/backends/cranelift/CraneliftBackend.java
index 7a16cc44..584fd7d0 100644
--- a/src/main/java/org/shedlang/compiler/backends/cranelift/CraneliftBackend.java
+++ b/src/main/java/org/shedlang/compiler/backends/cranelift/CraneliftBackend.java
@@ -1,23 +1,35 @@
package org.shedlang.compiler.backends.cranelift;
import com.google.flatbuffers.FlatBufferBuilder;
+import org.pcollections.PVector;
+import org.shedlang.compiler.backends.Backend;
+import org.shedlang.compiler.backends.PatioBackends;
import org.shedlang.compiler.backends.llvm.LlvmBackend;
import org.shedlang.compiler.backends.llvm.LlvmTarget;
import org.shedlang.compiler.backends.paths.PartialTargetPath;
+import org.shedlang.compiler.backends.paths.TargetDir;
+import org.shedlang.compiler.config.ProfileConfig;
+import org.shedlang.compiler.config.ProjectConfig;
import org.shedlang.compiler.filesystem.ShedCompilerFiles;
import org.shedlang.compiler.patio.PatioCompilationUnit;
import org.shedlang.compiler.patio.serialization.PatioToFlatbuffers;
import org.shedlang.compiler.runtime.ShedRuntime;
+import org.shedlang.compiler.shid.ShidNamespace;
+import org.shedlang.compiler.typechecker.TypeInfos;
+import org.shedlang.compiler.types.NamespaceName;
+import org.shedlang.compiler.util.P;
import org.shedlang.compiler.util.processes.ProcessError;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import static org.shedlang.compiler.util.processes.ProcessRunner.runInheritIo;
-public class CraneliftBackend {
+public class CraneliftBackend implements Backend {
public static final CraneliftBackend AMD64 = forTarget(LlvmTarget.AMD64);
public static CraneliftBackend forTarget(LlvmTarget target) {
@@ -34,20 +46,47 @@ public class CraneliftBackend {
PatioCompilationUnit patio,
PartialTargetPath partialTargetPath
) throws IOException, InterruptedException {
+ return compileCompilationUnit(patio, Optional.empty(), partialTargetPath);
+ }
+
+ private Path compileMain(
+ PatioCompilationUnit patio,
+ String mainFunctionName,
+ PartialTargetPath partialTargetPath
+ ) throws IOException, InterruptedException {
+ return compileCompilationUnit(patio, Optional.of(mainFunctionName), partialTargetPath);
+ }
+
+ private Path compileCompilationUnit(
+ PatioCompilationUnit patio,
+ Optional<String> mainFunctionName,
+ PartialTargetPath partialTargetPath
+ ) throws IOException, InterruptedException {
var fbsBuilder = new FlatBufferBuilder();
var compilationUnitOffset = PatioToFlatbuffers.serializeCompilationUnit(fbsBuilder, patio);
fbsBuilder.finish(compilationUnitOffset);
// TODO: avoid the copy
var patioPath = partialTargetPath.withExtension(".patio");
+ Files.createDirectories(patioPath.getParent());
Files.write(patioPath, fbsBuilder.sizedByteArray());
- runInheritIo(List.of(
- ShedCompilerFiles.getRoot().resolve("patio-to-cranelift/target/debug/patio-to-cranelift").toString(),
- patioPath.toString(),
- "--target",
- this.target.targetTriple()
- ));
+ var patioToCraneliftArgs = new ArrayList<String>();
+ patioToCraneliftArgs.add(
+ ShedCompilerFiles.getRoot()
+ .resolve("patio-to-cranelift/target/debug/patio-to-cranelift")
+ .toString()
+ );
+ patioToCraneliftArgs.add(patioPath.toString());
+ patioToCraneliftArgs.add("--target");
+ patioToCraneliftArgs.add(this.target.targetTriple());
+
+ if (mainFunctionName.isPresent()) {
+ patioToCraneliftArgs.add("--main");
+ patioToCraneliftArgs.add(mainFunctionName.get());
+ }
+
+ runInheritIo(patioToCraneliftArgs);
var objectFilePath = partialTargetPath.withExtension(".o");
return objectFilePath;
@@ -61,4 +100,87 @@ public class CraneliftBackend {
// TODO: extract linking if it's not specific to LLVM.
LlvmBackend.forTarget(this.target).link(inputs, outputPath, shedRuntime);
}
+
+ @Override
+ public String targetName() {
+ return "cranelift-" + target.targetName();
+ }
+
+ @Override
+ public void compile(
+ ProjectConfig config,
+ ProfileConfig profileConfig,
+ List<ShidNamespace> namespaces,
+ TypeInfos typeInfos,
+ TargetDir targetDir
+ ) throws IOException, InterruptedException {
+ PatioBackends.compile(
+ config,
+ profileConfig,
+ namespaces,
+ typeInfos,
+ new PatioToBinary(
+ targetDir,
+ P.vector()
+ )
+ );
+ }
+
+ private class PatioToBinary implements PatioBackends.PatioToTarget {
+ private final TargetDir targetDir;
+ private final PVector<Path> objectFilePaths;
+
+ public PatioToBinary(
+ TargetDir targetDir,
+ PVector<Path> objectFilePaths
+ ) {
+ this.targetDir = targetDir;
+ this.objectFilePaths = objectFilePaths;
+ }
+
+ @Override
+ public PatioBackends.PatioToTarget namespace(
+ NamespaceName namespaceName,
+ PatioCompilationUnit patioCompilationUnit
+ ) throws IOException, InterruptedException {
+ var objectPath = compileCompilationUnit(
+ patioCompilationUnit,
+ this.targetDir.namespace(namespaceName)
+ );
+
+ return new PatioToBinary(
+ this.targetDir,
+ this.objectFilePaths.plus(objectPath)
+ );
+ }
+
+ @Override
+ public void bin(
+ String binName,
+ PatioCompilationUnit patioCompilationUnit,
+ String mainFunctionName,
+ ProfileConfig profileConfig
+ ) throws IOException, InterruptedException {
+ var linkInputs = new ArrayList<>(objectFilePaths);
+
+ var mainObjectPath = compileMain(
+ patioCompilationUnit,
+ mainFunctionName,
+ this.targetDir.bin(binName)
+ );
+ linkInputs.add(mainObjectPath);
+
+ var shedRuntime = ShedRuntime.runtime(
+ target.targetName(),
+ profileConfig.gc(),
+ targetDir
+ );
+
+ link(
+ linkInputs,
+ targetDir.topLevel(binName),
+ shedRuntime
+ );
+ }
+ }
}
diff --git a/src/test/java/org/shedlang/compiler/backends/cranelift/CraneliftAmd64ExampleTests.java b/src/test/java/org/shedlang/compiler/backends/cranelift/CraneliftAmd64ExampleTests.java
new file mode 100644
index 00000000..bc78c435
--- /dev/null
+++ b/src/test/java/org/shedlang/compiler/backends/cranelift/CraneliftAmd64ExampleTests.java
@@ -0,0 +1,34 @@
+package org.shedlang.compiler.backends.cranelift;
+
+import org.junit.jupiter.api.Disabled;
+import org.shedlang.compiler.backends.Backend;
+import org.shedlang.compiler.backends.ExampleTests;
+
+import java.util.List;
+import java.util.Set;
+
+@Disabled
+public class CraneliftAmd64ExampleTests extends ExampleTests {
+ @Override
+ protected Backend backend() {
+ return CraneliftBackend.AMD64;
+ }
+
+ @Override
+ protected List<String> binaryRunner() {
+ return List.of();
+ }
+
+ @Override
+ protected String executableExtension() {
+ return "";
+ }
+
+ private static final Set<String> DISABLED = Set.of(
+ );
+
+ @Override
+ protected boolean isDisabled(String testName) {
+ return DISABLED.contains(testName);
+ }
+}