Skip to content

Commit

Permalink
Merge branch 'main' into treebuild
Browse files Browse the repository at this point in the history
  • Loading branch information
iwillspeak committed Aug 28, 2022
2 parents 535be4c + a2d595c commit eaf0fe8
Show file tree
Hide file tree
Showing 15 changed files with 369 additions and 225 deletions.
404 changes: 223 additions & 181 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ keywords = [ "llvm", "parser", "compiler" ]
categories = [ "parsing" ]
edition = "2018"

[features]
default = [ "llvm-13" ]

[dependencies]
llvm-sys = "90"
# FIXME: Want to upgrade to LLVM 10, but Clang doesn't seem capable of linking
# the IL or Bitcode output from it. Do we need to wait for LLVM 11? Is
# It time to stop relying on `cc` for linking?
# llvm-sys = { version = "100", git = "https://gitlab.com/iwillspeak/llvm-sys.rs.git", branch = "macos-tbd-link" }
llvm-9 = { package = "llvm-sys", version = "90", optional = true }
llvm-10 = { package = "llvm-sys", version = "100", optional = true }
llvm-13 = { package = "llvm-sys", version = "130", optional = true }
docopt = "1.1"
serde = { version = "1.0", features = ["derive"] }
tempfile = "3.1"
Expand Down
18 changes: 14 additions & 4 deletions azure-pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,28 @@ jobs:
- job: macOS
pool:
vmImage: 'macOS-10.15'
strategy:
matrix:
LLVM9:
llvm_tag: 'llvm\@9'
features: 'llvm-9'
llvm_ver: '90'
LLVM10:
llvm_tag: 'llvm'
features: 'llvm-10'
llvm_ver: '100'
steps:
- script: 'brew install llvm\@9'
- script: 'brew install $(llvm_tag)'
displayName: Brew install LLVM
- script: "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup.sh && sh rustup.sh -y"
displayName: Rustup
- script: |
export PATH=/usr/local/bin:$PATH # Local bin (brew)
source ~/.cargo/env
export LLVM_SYS_90_PREFIX=/usr/local/opt/llvm\@9
export LLVM_CONFIG_PATH=${LLVM_SYS_90_PREFIX}/bin/llvm-config
export LLVM_SYS_$(llvm_ver)_PREFIX=/usr/local/opt/$(llvm_tag)
export LLVM_CONFIG_PATH=${LLVM_SYS_$(llvm_ver)_PREFIX}/bin/llvm-config
cargo install just
./build.sh test
./build.sh features=$(features) test
displayName: './build.sh test'
- job: Linux
pool:
Expand Down
11 changes: 6 additions & 5 deletions justfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
features := "llvm-13"

build:
cargo build --release
cargo build --release --no-default-features --features={{features}}

test: build
cargo test
cargo test --no-default-features --features={{features}}
python3 specs.py

clean:
Expand Down Expand Up @@ -30,6 +32,5 @@ bench opt_level="3": build
except OSError:
pass
print("bench={0}, output={1}, opt={2}".format(bench, output, {{opt_level}}))
subprocess.call("target/release/ullage {0} -O{1} -o {2}"
.format(bench, {{opt_level}}, output))
subprocess.call("time {0}".format(output))
subprocess.call(["target/release/ullage", bench, "-O{{opt_level}}", "-o", output])
subprocess.call(["time", output])
5 changes: 3 additions & 2 deletions specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

Expectations = collections.namedtuple('Expectations', ['expects', 'failure_expects', 'skip_run'])

LINKER_KIND = "Object"
EXPECT_PATTERN = re.compile(r'#\s?=>\s?(.+)')
EXPECT_ERR_PATTERN = re.compile(r'#\s?!>\s?(.+)')
SKIP_PATTERN = re.compile(r'#\s?!!skip')
Expand Down Expand Up @@ -123,7 +124,7 @@ def run_spec(path):

expectations = parse_spec(path)
out = "specbin/{}".format(os.path.basename(path).split('.')[0])
compile_cmd = subprocess.Popen(["target/release/ullage", path, "-o", out], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
compile_cmd = subprocess.Popen(["target/release/ullage", path, "--link-kind", LINKER_KIND, "-o", out], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# Give the compiler 5 seconds to run, and return an error on timeout
timer = threading.Timer(5, compile_cmd.kill)
Expand All @@ -140,7 +141,7 @@ def run_spec(path):
run_cmd = subprocess.Popen(out, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = run_cmd.communicate()
if run_cmd.returncode != 0:
raise ExitCodeMismatchError("Expected successfull exit code")
raise ExitCodeMismatchError("Expected successfull exit code", run_cmd.returncode, output)
check_output(output[0].decode('utf-8'), expectations.expects)


Expand Down
11 changes: 7 additions & 4 deletions src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ use crate::diag::Diagnostic;
use crate::low_loader::prelude::*;
use crate::sem;
use crate::syntax;
use linker::Linker;
use std::path::Path;
use std::process::Command;
use tempfile::Builder;
use linker::Linker;

pub use self::error::{CompError, CompResult};
pub use self::options::{CompilationOptions, OptimisationLevel};

pub mod error;
pub mod options;
pub mod linker;
pub mod options;

mod lower;
mod lower_context;
Expand Down Expand Up @@ -110,7 +110,10 @@ impl Compilation {
let linker = self.options.linker.unwrap_or_else(Linker::default);

// Create a tempdir to write the LLVM IR or bitcode to
let temp_file = Builder::new().prefix("ullage").suffix(linker.asset_ty.extension()).tempfile()?;
let temp_file = Builder::new()
.prefix("ullage")
.suffix(linker.asset_ty.extension())
.tempfile()?;

// check if we have optimiation enabled and run the
// corresponding optimisations if we do.
Expand All @@ -122,7 +125,7 @@ impl Compilation {
if self.options.dump_ir {
module.dump();
}
module.write_to_file(temp_file.path())?;
module.write_to_file(&target, temp_file.path(), linker.asset_ty.file_kind())?;

// Shell out to Clang to link the final assembly
let output = Command::new(linker.cmd.executable())
Expand Down
26 changes: 21 additions & 5 deletions src/compile/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use std::default::Default;

use crate::low_loader::prelude::OutputFileKind;

/// The information for performing a link
pub struct Linker {
/// The linker command. Currently only `clang` is supported.
Expand All @@ -15,19 +17,21 @@ pub struct Linker {
}

/// The executable type to use for linking
#[derive(Debug,Copy,Clone)]
#[derive(Debug, Copy, Clone)]
pub enum LinkerCommand {
/// The Clang c compiler
Clang,
}

/// The intermediate asset type to pass to the linker
#[derive(Debug,Copy,Clone)]
#[derive(Debug, Copy, Clone)]
pub enum LinkerAssetType {
/// LLVM IR text files
LlvmIr,
/// LLVM IR bticode files
LlvmBc,
/// Native object
Object,
}

impl Linker {
Expand All @@ -38,7 +42,10 @@ impl Linker {

/// Create a linker from the given command
pub fn from_command(cmd: LinkerCommand) -> Self {
Linker { cmd, asset_ty: cmd.default_asset_ty() }
Linker {
cmd,
asset_ty: cmd.default_asset_ty(),
}
}
}

Expand All @@ -61,7 +68,7 @@ impl LinkerCommand {
// make the linker buidl the command
// rather than the compiler.
match *self {
LinkerCommand::Clang => "clang"
LinkerCommand::Clang => "clang",
}
}
}
Expand All @@ -73,12 +80,21 @@ impl Default for LinkerCommand {
}

impl LinkerAssetType {

/// Get the file extension for the asset type
pub fn extension(&self) -> &str {
match *self {
LinkerAssetType::LlvmIr => ".ll",
LinkerAssetType::LlvmBc => ".bc",
LinkerAssetType::Object => ".o",
}
}

/// Get the file kind for this asset type
pub(crate) fn file_kind(&self) -> OutputFileKind {
match *self {
LinkerAssetType::LlvmIr => OutputFileKind::LLVMIl,
LinkerAssetType::LlvmBc => OutputFileKind::Bitcode,
LinkerAssetType::Object => OutputFileKind::NativeObject,
}
}
}
8 changes: 5 additions & 3 deletions src/compile/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,11 @@ pub fn lower_internal(
Typ::Builtin(BuiltinType::String) => {
build_string_concat(ctx, builder, lhs_val, rhs_val)
}
_ => Err(CompError::from(
"invalid operand types for `Add`".to_string(),
))?,
_ => {
return Err(CompError::from(
"invalid operand types for `Add`".to_string(),
))
}
},
InfixOp::Sub => builder.build_sub(lhs_val, rhs_val),
InfixOp::Mul => builder.build_mul(lhs_val, rhs_val),
Expand Down
7 changes: 5 additions & 2 deletions src/compile/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
//! This module defines the options structure used to tweak
//! compilation output.
use crate::low_loader::pass_manager as pm;
use super::linker::Linker;
use crate::low_loader::pass_manager as pm;

/// Compilation Options
///
Expand Down Expand Up @@ -55,7 +55,10 @@ impl CompilationOptions {

/// Set the linker command to use
pub fn with_linker(self, linker: Linker) -> Self {
CompilationOptions { linker: Some(linker), ..self }
CompilationOptions {
linker: Some(linker),
..self
}
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/low_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@
#![deny(missing_docs)]

use llvm_sys;
#[cfg(feature = "llvm-10")]
use llvm_10 as llvm_sys;
#[cfg(feature = "llvm-13")]
use llvm_13 as llvm_sys;
#[cfg(feature = "llvm-9")]
use llvm_9 as llvm_sys;

pub mod builder;
pub mod context;
Expand All @@ -42,7 +47,7 @@ pub mod prelude {
pub use super::builder::Predicate;
pub use super::context::Context;
pub use super::function::{CallConvention, Function};
pub use super::module::Module;
pub use super::module::{Module, OutputFileKind};
pub use super::targets::{Target, TargetLookupError};
pub use super::types::Type;
pub use super::value::Value;
Expand Down
4 changes: 4 additions & 0 deletions src/low_loader/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ impl Function {
///
/// Takes ownership of the given function and provides more
/// stronlgy typed access to it.
///
/// # Safety
///
/// The value should be a function. This is not checked.
pub unsafe fn from_raw(raw: LLVMValueRef) -> Self {
Function {
raw,
Expand Down
61 changes: 53 additions & 8 deletions src/low_loader/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use super::function::Function;
use super::llvm_sys::prelude::*;
use super::llvm_sys::target_machine;
use super::llvm_sys::{analysis, bit_writer, core};
use super::pass_manager::{OptLevel, OptSize, PassManagerBuilder};
use super::targets::Target;
Expand All @@ -22,6 +23,19 @@ pub struct Module {
raw: LLVMModuleRef,
}

/// The kind of output file to write
///
/// Used when writing modules to disk.
#[derive(Debug, PartialEq)]
pub enum OutputFileKind {
/// LLVM IL files
LLVMIl,
/// LLVM Bitcode file
Bitcode,
/// Native executable object files
NativeObject,
}

impl Module {
/// Module from Raw
///
Expand Down Expand Up @@ -90,18 +104,49 @@ impl Module {

/// Write the Module to the Given File as LLVM IR or Bitcode
///
/// If the path's extension is `.ll` then the file is written as
/// LLVM IR, otherwise the file is written as bitcode.
pub fn write_to_file(&self, path: &Path) -> Result<(), String> {
let is_il = path.extension().map(|e| e == "ll").unwrap_or(false);
/// The kind of file written depends on `kind`.
pub fn write_to_file(
&self,
target: &Target,
path: &Path,
kind: OutputFileKind,
) -> Result<(), String> {
let path = path.to_str().and_then(|s| CString::new(s).ok()).unwrap();

unsafe {
let mut message = ptr::null_mut();
let r = if is_il {
core::LLVMPrintModuleToFile(self.raw, path.as_ptr(), &mut message)
} else {
bit_writer::LLVMWriteBitcodeToFile(self.raw, path.as_ptr())
let r = match kind {
OutputFileKind::LLVMIl => {
core::LLVMPrintModuleToFile(self.raw, path.as_ptr(), &mut message)
}
OutputFileKind::Bitcode => {
bit_writer::LLVMWriteBitcodeToFile(self.raw, path.as_ptr())
}
OutputFileKind::NativeObject => {
let trip = CString::new(target.triple()).unwrap();
// To emit code we need to do a few things:
// * Create an LLVM TargetMachine from our target.
// * Create a pass manager
// * Call targetMachine emit to file
let tm = target_machine::LLVMCreateTargetMachine(
target.as_llvm_target(),
trip.as_ptr(),
target_machine::LLVMGetHostCPUName(),
target_machine::LLVMGetHostCPUFeatures(),
target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault,
target_machine::LLVMRelocMode::LLVMRelocDefault,
target_machine::LLVMCodeModel::LLVMCodeModelSmall,
);
let r = target_machine::LLVMTargetMachineEmitToFile(
tm,
self.as_raw(),
path.as_ptr() as *mut _,
target_machine::LLVMCodeGenFileType::LLVMObjectFile,
&mut message,
);
target_machine::LLVMDisposeTargetMachine(tm);
r
}
};
if r == 0 {
Ok(())
Expand Down
Loading

0 comments on commit eaf0fe8

Please sign in to comment.