Skip to content

Commit

Permalink
misc: upgrade to LLVM 12.0.1
Browse files Browse the repository at this point in the history
Backwards incompatible changes to LLVM IR require specifying of a type
for sret attribute
  • Loading branch information
Wodann committed Feb 21, 2022
1 parent 76d2ee1 commit 573983e
Show file tree
Hide file tree
Showing 15 changed files with 4,754 additions and 4,686 deletions.
9,288 changes: 4,668 additions & 4,620 deletions .github/actions/install-llvm/dist/index.js

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions .github/actions/install-llvm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export async function execute(cmd) {
let myError = '';
await exec.exec(cmd, [], {
listeners: {
stdout: (data) => {
myOutput += data.toString().trim();
},
stderr: (data) => {
myError += data.toString().trim();
}
stdout: (data) => {
myOutput += data.toString().trim();
},
stderr: (data) => {
myError += data.toString().trim();
}
}
});

Expand All @@ -29,30 +29,30 @@ export async function execute(cmd) {

(async () => {
try {
if(isLinux) {
if (isLinux) {
const installScript = path.join(__dirname, "../../../../scripts/install-llvm.sh");
await exec.exec(`sudo ${installScript}`);
} else if(isMacOS) {
await exec.exec("brew install llvm@11")
let llvmPath = await execute("brew --prefix llvm@11");
core.addPath(`${llvmPath}/bin`)
} else if(isWindows) {
const downloadUrl = "https://github.com/mun-lang/llvm-package-windows/releases/download/v11.0.1/llvm-11.0.1-windows-x64-msvc16.7z"
} else if (isMacOS) {
await exec.exec("brew install llvm@12")
let llvmPath = await execute("brew --prefix llvm@12");
core.addPath(`${llvmPath}/bin`)
} else if (isWindows) {
const downloadUrl = "https://github.com/mun-lang/llvm-package-windows/releases/download/v12.0.1/llvm-12.0.1-windows-x64-msvc16.7z"
core.info(`downloading LLVM from '${downloadUrl}'`)
const downloadLocation = await tc.downloadTool(downloadUrl);

core.info("Succesfully downloaded LLVM release, extracting...")
const llvmPath = path.resolve("llvm");
const _7zPath = path.join(__dirname, '..', 'externals', '7zr.exe');
let attempt = 1;
while(true) {
while (true) {
const args = [
"x", // extract
downloadLocation,
`-o${llvmPath}`
]
const exit = await exec.exec(_7zPath, args);
if(exit === 2 && attempt <= 4) {
if (exit === 2 && attempt <= 4) {
attempt += 1;
console.error(`Error extracting LLVM release, retrying attempt #${attempt} after 1s..`)
await new Promise(resolve => setTimeout(resolve, 1000));
Expand All @@ -70,8 +70,8 @@ export async function execute(cmd) {
core.exportVariable('LIBCLANG_PATH', `${llvmPath}/bin`)
} else {
core.setFailed(`unsupported platform '${process.platform}'`)
}
} catch(error) {
}
} catch (error) {
console.error(error.stack);
core.setFailed(error.message);
}
Expand Down
26 changes: 13 additions & 13 deletions book/src/ch04-02-building-llvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The Mun compiler makes heavy use of LLVM for all code-generation capabilities.
Installing it, however, can be tricky.
This document is a short guide on how to install LLVM on your machine so you can build Mun yourself.

Currently, Mun targets LLVM 11 so everything in this document refers to that version.
Currently, Mun targets LLVM 12 so everything in this document refers to that version.
However, these instructions should also hold for newer versions.

## Prebuild binaries
Expand All @@ -21,10 +21,10 @@ For Windows, [we maintain a repository](https://github.com/mun-lang/llvm-package
These releases are also used on our CI runners.

To use a release, download and extract it to your machine.
To make sure the build pipeline can find the binaries, add an environment variable called `LLVM_SYS_110_PREFIX` that points to the folder where you extracted the release.
To make sure the build pipeline can find the binaries, add an environment variable called `LLVM_SYS_120_PREFIX` that points to the folder where you extracted the release.
It is also possible to add the `bin` folder of the release to your path but using the environment variables allows you to have multiple LLVM releases on your machine.

> For LLVM 8 you should add the `LLVM_SYS_80_PREFIX` environment variable, for LLVM 11 add `LLVM_SYS_110_PREFIX`.
> For LLVM 8 you should add the `LLVM_SYS_80_PREFIX` environment variable, for LLVM 12 add `LLVM_SYS_120_PREFIX`.
### Debian & Ubuntu

Expand All @@ -38,7 +38,7 @@ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -

# Add the repository
# ${REPO_NAME} should be something like:
# deb http://apt.llvm.org/focal/ llvm-toolchain-focal-11 main
# deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main
#
# The `add-apt-repository` command is installed by the `software-properties-common` package:
# sudo apt install software-properties-common
Expand All @@ -48,26 +48,26 @@ add-apt-repository "${REPO_NAME}"
Once you have the proper APT repository configured you can install the required LLVM binaries with:

```bash
apt install llvm-11 llvm-11-* liblld-11* libclang-common-11-dev
apt install llvm-12 llvm-12-* liblld-12* libclang-common-12-dev
```

### MacOS

[Brew](https://brew.sh/) contains a cask for LLVM that can be used to build Mun:

```bash
brew install llvm@11
brew install llvm@12
```

After installing LLVM, you can either add the `bin` folder of the release to your path; or you can add a release-specific environment variable called `LLVM_SYS_110_PREFIX` that points to the release:
After installing LLVM, you can either add the `bin` folder of the release to your path; or you can add a release-specific environment variable called `LLVM_SYS_120_PREFIX` that points to the release:

```bash
export LLVM_SYS_110_PREFIX=$(brew --prefix llvm@11)
export LLVM_SYS_120_PREFIX=$(brew --prefix llvm@12)
```

Adding the `LLVM_SYS_110_PREFIX` variable is usually easier because the LLVM binaries will not conflict with any preinstalled version of LLVM and it allows you to easily install another version of LLVM side-by-side.
Adding the `LLVM_SYS_120_PREFIX` variable is usually easier because the LLVM binaries will not conflict with any preinstalled version of LLVM and it allows you to easily install another version of LLVM side-by-side.

> For LLVM 8 you should add the `LLVM_SYS_80_PREFIX` environment variable, for LLVM 11 add `LLVM_SYS_110_PREFIX`.
> For LLVM 8 you should add the `LLVM_SYS_80_PREFIX` environment variable, for LLVM 12 add `LLVM_SYS_120_PREFIX`.
## Building from source

Expand All @@ -83,18 +83,18 @@ Download a dump of the LLVM repository from the [LLVM github repository](https:/

```bash
wget -qO- \
https://github.com/llvm/llvm-project/archive/llvmorg-11.0.1.tar.gz | \
https://github.com/llvm/llvm-project/archive/llvmorg-12.0.1.tar.gz | \
tar xzf -
```

Then build the required components and install them to `~/local`.

```bash
cd llvm-project-llvmorg-11.0.1/llvm
cd llvm-project-llvmorg-12.0.1/llvm
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="lld;clang" -DCMAKE_INSTALL_PREFIX=$HOME/local -DCMAKE_INSTALL_PREFIX=$HOME/local -DLLVM_ENABLE_LIBXML2=OFF
make install -j
```

After LLVM is build, make sure to add the `$HOME/local/bin` to you path or add an environment variable `LLVM_SYS_110_PREFIX` (or `LLVM_SYS_110_PREFIX` depending on the LLVM version you installed) that points to `$HOME/local`.
After LLVM is build, make sure to add the `$HOME/local/bin` to you path or add an environment variable `LLVM_SYS_120_PREFIX` (or `LLVM_SYS_120_PREFIX` depending on the LLVM version you installed) that points to `$HOME/local`.
4 changes: 2 additions & 2 deletions crates/mun_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ hir = { version = "=0.3.0", path = "../mun_hir", package = "mun_hir" }
itertools = "0.9.0"
mun_codegen_macros = { version = "=0.1.0", path = "../mun_codegen_macros", package = "mun_codegen_macros" }
mun_target = { version = "=0.3.0", path = "../mun_target" }
mun_lld = { version = "=110.0.0", path = "../mun_lld" }
mun_lld = { version = "=120.0.1", path = "../mun_lld" }
anyhow = "1.0.31"
thiserror = "1.0.19"
salsa = "0.16.1"
Expand All @@ -29,7 +29,7 @@ array-init="0.1.0"
tempfile = "3"
paste = "0.1.6"
parking_lot = "0.11.1"
inkwell = { version = "=0.1.0-beta.2", features = ["llvm11-0", "no-libffi-linking"]}
inkwell = { version = "=0.1.0-beta.4", features = ["llvm12-0", "no-libffi-linking"]}
by_address = "1.0.4"
paths = { version="=0.1.0", path="../mun_paths", package="mun_paths"}
smallvec = "1.6.1"
Expand Down
16 changes: 9 additions & 7 deletions crates/mun_codegen/src/code_gen/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ use crate::{
type_table::TypeTable,
},
type_info::TypeInfo,
value::{AsValue, CanInternalize, Global, IrValueContext, IterAsIrValue, Value},
value::{
AsValue, CanInternalize, Global, IrValueContext, IterAsIrValue, SizedValueType, Value,
},
};
use hir::{HirDatabase, Ty};
use inkwell::{attributes::Attribute, module::Linkage};
use inkwell::{attributes::Attribute, module::Linkage, types::AnyType};
use std::convert::TryFrom;
use std::{collections::HashSet, ffi::CString};

Expand Down Expand Up @@ -288,12 +290,12 @@ fn gen_get_info_fn<'ink>(
.add_function("get_info", get_symbols_type, Some(Linkage::DLLExport));

if target.options.is_like_windows {
get_symbols_fn.add_attribute(
inkwell::attributes::AttributeLoc::Param(0),
context
.context
.create_enum_attribute(Attribute::get_named_enum_kind_id("sret"), 0),
let type_attribute = context.context.create_type_attribute(
Attribute::get_named_enum_kind_id("sret"),
ir::AssemblyInfo::get_ir_type(context.type_context).as_any_type_enum(),
);

get_symbols_fn.add_attribute(inkwell::attributes::AttributeLoc::Param(0), type_attribute);
}

let builder = context.context.create_builder();
Expand Down
2 changes: 1 addition & 1 deletion crates/mun_codegen/src/intrinsics/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ macro_rules! intrinsics{
}

fn ir_type<'ink>(&self, context: &'ink Context, target: &TargetData) -> FunctionType<'ink> {
let args = vec![$(<$arg as crate::ir::IsBasicIrType>::ir_type(context, target)),*];
let args = vec![$(<$arg as crate::ir::IsBasicIrType>::ir_type(context, target).into()),*];
<$ret as crate::ir::IsFunctionReturnType>::fn_type(context, target, &args, false)
}
}
Expand Down
15 changes: 8 additions & 7 deletions crates/mun_codegen/src/ir.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use inkwell::context::Context;
use inkwell::targets::TargetData;
use inkwell::types::{
AnyType, BasicType, BasicTypeEnum, FloatType, FunctionType, IntType, PointerType,
AnyType, BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FloatType, FunctionType, IntType,
PointerType,
};
use inkwell::AddressSpace;

Expand Down Expand Up @@ -41,7 +42,7 @@ pub trait IsFunctionReturnType<'ink> {
fn fn_type(
context: &'ink Context,
target: &TargetData,
arg_types: &[BasicTypeEnum<'ink>],
arg_types: &[BasicMetadataTypeEnum<'ink>],
is_var_args: bool,
) -> FunctionType<'ink>;
}
Expand All @@ -51,7 +52,7 @@ impl<'ink, T: IsBasicIrType<'ink>> IsFunctionReturnType<'ink> for T {
fn fn_type(
context: &'ink Context,
target: &TargetData,
arg_types: &[BasicTypeEnum<'ink>],
arg_types: &[BasicMetadataTypeEnum<'ink>],
is_var_args: bool,
) -> FunctionType<'ink> {
T::ir_type(context, target).fn_type(arg_types, is_var_args)
Expand All @@ -62,7 +63,7 @@ impl<'ink> IsFunctionReturnType<'ink> for () {
fn fn_type(
context: &'ink Context,
_target: &TargetData,
arg_types: &[BasicTypeEnum<'ink>],
arg_types: &[BasicMetadataTypeEnum<'ink>],
is_var_args: bool,
) -> FunctionType<'ink> {
context.void_type().fn_type(arg_types, is_var_args)
Expand Down Expand Up @@ -92,7 +93,7 @@ pub trait AsFunctionReturnType<'ink> {
&self,
context: &'ink Context,
target: &TargetData,
arg_types: &[BasicTypeEnum<'ink>],
arg_types: &[BasicMetadataTypeEnum<'ink>],
is_var_args: bool,
) -> FunctionType<'ink>;
}
Expand All @@ -102,7 +103,7 @@ impl<'ink, T: AsBasicIrType<'ink>> AsFunctionReturnType<'ink> for T {
&self,
context: &'ink Context,
target: &TargetData,
arg_types: &[BasicTypeEnum<'ink>],
arg_types: &[BasicMetadataTypeEnum<'ink>],
is_var_args: bool,
) -> FunctionType<'ink> {
self.as_ir_type(context, target)
Expand All @@ -115,7 +116,7 @@ impl<'ink> AsFunctionReturnType<'ink> for () {
&self,
context: &'ink Context,
_target: &TargetData,
arg_types: &[BasicTypeEnum<'ink>],
arg_types: &[BasicMetadataTypeEnum<'ink>],
is_var_args: bool,
) -> FunctionType<'ink> {
context.void_type().fn_type(arg_types, is_var_args)
Expand Down
16 changes: 11 additions & 5 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use hir::{
Literal, LogicOp, Name, Ordering, Pat, PatId, Path, ResolveBitness, Resolver, Statement,
TyKind, UnaryOp, ValueNs,
};
use inkwell::values::BasicMetadataValueEnum;
use inkwell::{
basic_block::BasicBlock,
builder::Builder,
Expand Down Expand Up @@ -152,7 +153,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {

pub fn gen_fn_wrapper(&mut self) {
let fn_sig = self.hir_function.ty(self.db).callable_sig(self.db).unwrap();
let args: Vec<BasicValueEnum> = fn_sig
let args: Vec<BasicMetadataValueEnum> = fn_sig
.params()
.iter()
.enumerate()
Expand All @@ -167,6 +168,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
} else {
param
}
.into()
})
.collect();

Expand Down Expand Up @@ -230,9 +232,9 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
match self.infer[*callee].as_callable_def() {
Some(hir::CallableDef::Function(def)) => {
// Get all the arguments
let args: Vec<BasicValueEnum> = args
let args: Vec<BasicMetadataValueEnum> = args
.iter()
.map(|expr| self.gen_expr(*expr).expect("expected a value"))
.map(|expr| self.gen_expr(*expr).expect("expected a value").into())
.collect();

self.gen_call(def, &args)
Expand Down Expand Up @@ -397,7 +399,11 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
// make it struct type agnostic, it is stored in a `*const *mut std::ffi::c_void`.
let object_ptr = self
.builder
.build_call(new_fn_ptr, &[type_info_ptr, allocator_handle], "new")
.build_call(
new_fn_ptr,
&[type_info_ptr.into(), allocator_handle.into()],
"new",
)
.try_as_basic_value()
.left()
.unwrap()
Expand Down Expand Up @@ -1068,7 +1074,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
fn gen_call(
&mut self,
function: hir::Function,
args: &[BasicValueEnum<'ink>],
args: &[BasicMetadataValueEnum<'ink>],
) -> CallSiteValue<'ink> {
if self.should_use_dispatch_table(function) {
let ptr_value = self.dispatch_table.gen_function_lookup(
Expand Down
11 changes: 7 additions & 4 deletions crates/mun_codegen/src/ir/dispatch_table.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::module_group::ModuleGroup;
use crate::{intrinsics::Intrinsic, ir::function, ir::ty::HirTypeCache, type_info::TypeInfo};
use hir::{Body, Expr, ExprId, HirDatabase, InferenceResult};
use inkwell::values::CallableValue;
use inkwell::{
context::Context,
module::Module,
targets::TargetData,
types::{BasicTypeEnum, FunctionType},
values::{BasicValueEnum, PointerValue},
values::BasicValueEnum,
};
use rustc_hash::FxHashSet;
use std::{
Expand Down Expand Up @@ -80,7 +81,7 @@ impl<'ink> DispatchTable<'ink> {
table_ref: Option<inkwell::values::GlobalValue<'ink>>,
builder: &inkwell::builder::Builder<'ink>,
function: hir::Function,
) -> PointerValue<'ink> {
) -> CallableValue<'ink> {
let function_name = function.name(db).to_string();

// Get the index of the function
Expand All @@ -100,7 +101,7 @@ impl<'ink> DispatchTable<'ink> {
table_ref: Option<inkwell::values::GlobalValue<'ink>>,
builder: &inkwell::builder::Builder<'ink>,
intrinsic: &impl Intrinsic,
) -> PointerValue<'ink> {
) -> CallableValue<'ink> {
let prototype = intrinsic.prototype(self.context, &self.target);

// Get the index of the intrinsic
Expand All @@ -120,7 +121,7 @@ impl<'ink> DispatchTable<'ink> {
builder: &inkwell::builder::Builder<'ink>,
function_name: &str,
index: usize,
) -> PointerValue<'ink> {
) -> CallableValue<'ink> {
// Get the internal table reference
let table_ref = table_ref.expect("no dispatch table defined");

Expand All @@ -141,6 +142,8 @@ impl<'ink> DispatchTable<'ink> {
builder
.build_load(ptr_to_function_ptr, &format!("{0}_ptr", function_name))
.into_pointer_value()
.try_into()
.expect("Pointer value is not a valid function pointer.")
}

/// Returns the value that represents the dispatch table in IR or `None` if no table was
Expand Down
Loading

0 comments on commit 573983e

Please sign in to comment.