Skip to content
This repository was archived by the owner on Jan 18, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 13 additions & 30 deletions artiq/compiler/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from artiq.compiler import types, ir
from llvmlite import ir as ll, binding as llvm

llvm.initialize()
llvm.initialize_all_targets()
llvm.initialize_all_asmprinters()

Expand Down Expand Up @@ -108,35 +107,19 @@ def target_machine(self):
return llmachine

def optimize(self, llmodule):
llpassmgr = llvm.create_module_pass_manager()

# Register our alias analysis passes.
llpassmgr.add_basic_alias_analysis_pass()
llpassmgr.add_type_based_alias_analysis_pass()

# Start by cleaning up after our codegen and exposing as much
# information to LLVM as possible.
llpassmgr.add_constant_merge_pass()
llpassmgr.add_cfg_simplification_pass()
llpassmgr.add_instruction_combining_pass()
llpassmgr.add_sroa_pass()
llpassmgr.add_dead_code_elimination_pass()
llpassmgr.add_function_attrs_pass()
llpassmgr.add_global_optimizer_pass()

# Now, actually optimize the code.
llpassmgr.add_function_inlining_pass(275)
llpassmgr.add_ipsccp_pass()
llpassmgr.add_instruction_combining_pass()
llpassmgr.add_gvn_pass()
llpassmgr.add_cfg_simplification_pass()
llpassmgr.add_licm_pass()

# Clean up after optimizing.
llpassmgr.add_dead_arg_elimination_pass()
llpassmgr.add_global_dce_pass()

llpassmgr.run(llmodule)
llmachine = self.target_machine()
pto = llvm.create_pipeline_tuning_options(size_level=1)

# This combination of levels gets mapped to the -Os PassManagerBuilder default in
# llvmlite 0.45. The mapping is slightly nonsensical in that -Oz (which is more
# aggressively optimizing for size at the expense of runtime) is accessed via
# speed_level=size_level=2.
pto.speed_level = 1

pb = llvm.create_pass_builder(llmachine, pto)
llpassmgr = pb.getModulePassManager()

llpassmgr.run(llmodule, pb)

def compile(self, module):
"""Compile the module to a relocatable object for this target."""
Expand Down
1 change: 1 addition & 0 deletions artiq/firmware/ksupport/ksupport.ld
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,6 @@ SECTIONS
/DISCARD/ :
{
*(.debug*)
*(.riscv.attributes)
}
}
2 changes: 1 addition & 1 deletion artiq/test/lit/embedding/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from artiq.language.core import *
from artiq.language.types import *

# CHECK: i64 @_Z13testbench.foozz\(i64 %ARG.x, \{ i1, i64 \} %ARG.y\)
# CHECK-L: i64 @_Z13testbench.foozz(i64

@kernel
def foo(x: TInt64, y: TInt64 = 1) -> TInt64:
Expand Down
6 changes: 3 additions & 3 deletions artiq/test/lit/embedding/annotation_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
from artiq.language.core import *
from artiq.language.types import *

# CHECK-L: i64 @_Z13testbench.foozz(i64 %ARG.x, { i1, i32 } %ARG.y)
# CHECK-L: i64 @_Z13testbench.foozz(i64

@kernel
def foo(x: np.int64, y: np.int32 = 1) -> np.int64:
print(x + y)
return x + y

# CHECK-L: void @_Z13testbench.barzz()
# CHECK-L: void @_Z13testbench.barzz(i32
@kernel
def bar(x: np.int32) -> None:
print(x)

# CHECK-L: @_Z21testbench.unpack_listzz({ i1, i64 }* nocapture writeonly sret({ i1, i64 }) %.1, { i64*, i32 }* %ARG.xs)
# CHECK-L: @_Z21testbench.unpack_listzz(ptr
@kernel
def unpack_list(xs: List[np.int64]) -> Tuple[bool, np.int64]:
print(xs)
Expand Down
2 changes: 1 addition & 1 deletion artiq/test/lit/embedding/index_tuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from artiq.language.core import *
from artiq.language.types import *

# CHECK-L: void @_Z16testbench.unpackzz({ i32, { i8*, i32 }, i1 } %ARG.x)
# CHECK-L: void @_Z16testbench.unpackzz({ i32, { ptr, i32 }, i1 } %ARG.x)

@kernel
def unpack(x):
Expand Down
4 changes: 2 additions & 2 deletions artiq/test/lit/embedding/invariant_propagation.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def run(self):
if self.foo:
print("bar")
else:
# Make sure all the code for this branch will be completely elided:
# CHECK-NOT: baz
# The kernel_invariant annotation should generate !invariant.load metadata
# CHECK: invariant.load
print("baz")

obj = Class()
Expand Down
4 changes: 2 additions & 2 deletions artiq/test/lit/embedding/subkernel_message_recv.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ def entrypoint():
# CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !.
message_pass()
# CHECK-NOT: call void @subkernel_send_message\(i32 ., i1 false, i8 1, i8 1, .*\), !dbg !.
# CHECK: call i8 @subkernel_await_message\(i32 2, i64 -1, { i8\*, i32 }\* nonnull .*, i8 1, i8 1\), !dbg !.
# CHECK: call i8 @subkernel_await_message\(i32 2, i64 -1, ptr nonnull .*, i8 1, i8 1\), !dbg !.
subkernel_recv("message", TInt32)


# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr
# CHECK-NOT-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr
# CHECK-L: declare i8 @subkernel_await_message(i32, i64, { i8*, i32 }*, i8, i8) local_unnamed_addr
# CHECK-L: declare i8 @subkernel_await_message(i32, i64, ptr, i8, i8) local_unnamed_addr
# CHECK-NOT-L: declare void @subkernel_await_finish(i32, i64) local_unnamed_addr
@subkernel(destination=1)
def message_pass() -> TNone:
Expand Down
2 changes: 1 addition & 1 deletion artiq/test/lit/embedding/subkernel_message_send.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def entrypoint():


# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr
# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr
# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, ptr, ptr) local_unnamed_addr
@subkernel(destination=1)
def message_pass() -> TNone:
subkernel_recv("message", TInt32)
4 changes: 2 additions & 2 deletions artiq/test/lit/embedding/subkernel_return.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ def entrypoint():
# CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !.
# CHECK-NOT: call void @subkernel_send_message\(.*\), !dbg !.
returning()
# CHECK: call i8 @subkernel_await_message\(i32 1, i64 -1, { i8\*, i32 }\* nonnull .*, i8 1, i8 1\), !dbg !.
# CHECK: call i8 @subkernel_await_message\(i32 1, i64 -1, ptr nonnull .*, i8 1, i8 1\), !dbg !.
# CHECK: call void @subkernel_await_finish\(i32 1, i64 -1\), !dbg !.
subkernel_await(returning)

# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr
# CHECK-NOT-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr
# CHECK-L: declare i8 @subkernel_await_message(i32, i64, { i8*, i32 }*, i8, i8) local_unnamed_addr
# CHECK-L: declare i8 @subkernel_await_message(i32, i64, ptr, i8, i8) local_unnamed_addr
# CHECK-L: declare void @subkernel_await_finish(i32, i64) local_unnamed_addr
@subkernel(destination=1)
def returning() -> TInt32:
Expand Down
2 changes: 1 addition & 1 deletion artiq/test/lit/embedding/subkernel_self_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ def entrypoint():
a.kernel_entrypoint()

# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr
# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr
# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, ptr, ptr) local_unnamed_addr
2 changes: 1 addition & 1 deletion artiq/test/lit/embedding/subkernel_with_arg.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def entrypoint():


# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr
# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr
# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, ptr, ptr) local_unnamed_addr
@subkernel(destination=1)
def accept_arg(arg: TInt32) -> TNone:
pass
2 changes: 1 addition & 1 deletion artiq/test/lit/embedding/subkernel_with_opt_arg.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def entrypoint():


# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr
# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr
# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, ptr, ptr) local_unnamed_addr
@subkernel(destination=1)
def accept_arg(arg_a, arg_b=5) -> TNone:
pass
8 changes: 4 additions & 4 deletions artiq/test/lit/embedding/syscall_arg_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@

@kernel
def entrypoint():
# CHECK: call void @accept_str\({ i8\*, i32 }
# CHECK: call void @accept_str\({ ptr, i32 }
accept_str("foo")

# CHECK: call void @return_str\({ i8\*, i32 }\* nonnull sret
# CHECK: call void @return_str\(ptr nonnull sret
return_str()


# CHECK: declare void @accept_str\({ i8\*, i32 }\)
# CHECK: declare void @accept_str\({ ptr, i32 }\)
@syscall
def accept_str(name: TStr) -> TNone:
pass


# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\({ i8\*, i32 }\)\)
# CHECK: declare void @return_str\(ptr sret\({ ptr, i32 }\)\)
@syscall
def return_str() -> TStr:
pass
4 changes: 2 additions & 2 deletions artiq/test/lit/embedding/syscall_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# CHECK: call void @foo\(\)(, !dbg !\d+)?

# CHECK-L: ; Function Attrs: inaccessiblememonly nounwind
# CHECK-L: ; Function Attrs: nounwind memory(inaccessiblemem: readwrite)
# CHECK-NEXT-L: declare void @foo()

@syscall(flags={"nounwind", "nowrite"})
Expand All @@ -15,7 +15,7 @@ def foo() -> TNone:

# sret nowrite functions shouldn't be marked inaccessiblememonly.
# CHECK-L: ; Function Attrs: nounwind
# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret({ i32, i64 }))
# CHECK-NEXT-L: declare void @bar(ptr sret({ i32, i64 }))
@syscall(flags={"nounwind", "nowrite"})
def bar() -> TTuple([TInt32, TInt64]):
pass
Expand Down
57 changes: 15 additions & 42 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@
QML2_IMPORT_PATH = "${qtbase}/${qtQmlPrefix}";
};

inherit (pkgs.callPackage ./llvm {}) llvm_15 lld_15 llvmPackages_15;

rust = pkgs.rust-bin.nightly."2021-09-01".default.override {
extensions = ["rust-src"];
targets = [];
Expand Down Expand Up @@ -158,30 +156,6 @@
'';
};

llvmlite-new = pkgs.python3Packages.buildPythonPackage rec {
pname = "llvmlite";
version = "0.44.0";
src = pkgs.fetchFromGitHub {
owner = "numba";
repo = "llvmlite";
rev = "v${version}";
sha256 = "sha256-ZIA/JfK9ZP00Zn6SZuPus30Xw10hn3DArHCkzBZAUV0=";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
nativeBuildInputs = [llvm_15];
# Disable static linking
# https://github.com/numba/llvmlite/issues/93
postPatch = ''
substituteInPlace ffi/Makefile.linux --replace "-static-libstdc++" ""
substituteInPlace llvmlite/tests/test_binding.py --replace "test_linux" "nope"
'';
# Set directory containing llvm-config binary
preConfigure = ''
export LLVM_CONFIG=${llvm_15.dev}/bin/llvm-config
'';
};

artiq-upstream = pkgs.python3Packages.buildPythonPackage rec {
pname = "artiq";
version = artiqVersion;
Expand All @@ -195,10 +169,9 @@
'';

nativeBuildInputs = [pkgs.qt6.wrapQtAppsHook];
# keep llvm_x and lld_x in sync with llvmlite
propagatedBuildInputs =
[llvm_15 lld_15 sipyco.packages.x86_64-linux.sipyco pythonparser llvmlite-new pkgs.qt6.qtsvg artiq-comtools.packages.x86_64-linux.artiq-comtools]
++ (with pkgs.python3Packages; [pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt6 qasync tqdm lmdb jsonschema platformdirs]);
[pkgs.llvm_20 pkgs.lld_20 sipyco.packages.x86_64-linux.sipyco pythonparser pkgs.qt6.qtsvg artiq-comtools.packages.x86_64-linux.artiq-comtools]
++ (with pkgs.python3Packages; [llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt6 qasync tqdm lmdb jsonschema platformdirs]);

dontWrapQtApps = true;
postFixup = ''
Expand All @@ -219,10 +192,10 @@
"--set FONTCONFIG_FILE ${pkgs.fontconfig.out}/etc/fonts/fonts.conf"
];

# FIXME: automatically propagate lld_15 llvm_15 dependencies
# FIXME: automatically propagate lld_20 llvm_20 dependencies
# cacert is required in the check stage only, as certificates are to be
# obtained from system elsewhere
nativeCheckInputs = [lld_15 llvm_15 libartiq-support pkgs.lit pkgs.outputcheck pkgs.cacert];
nativeCheckInputs = with pkgs; [lld_20 llvm_20 lit outputcheck cacert] ++ [libartiq-support];
checkPhase = ''
python -m unittest discover -v artiq.test

Expand Down Expand Up @@ -308,9 +281,9 @@
nativeBuildInputs = [
(pkgs.python3.withPackages (ps: [migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ps.packaging]))
rust
llvm_15
lld_15
llvmPackages_15.clang-unwrapped
pkgs.llvm_20
pkgs.lld_20
pkgs.llvmPackages_20.clang-unwrapped
vivado
];
overrideMain = _: {
Expand Down Expand Up @@ -498,6 +471,9 @@
[
git
lit
lld_20
llvm_20
llvmPackages_20.clang-unwrapped
outputcheck
pdf2svg

Expand All @@ -510,9 +486,6 @@
(python3.withPackages (ps: [migen misoc microscope ps.packaging ps.paramiko] ++ artiq.propagatedBuildInputs))
]
++ [
llvm_15
lld_15
llvmPackages_15.clang-unwrapped
rust
latex-artiq-manual
artiq-frontend-dev-wrappers
Expand All @@ -538,9 +511,9 @@
packages = [
rust

llvm_15
lld_15
llvmPackages_15.clang-unwrapped
pkgs.llvm_20
pkgs.lld_20
pkgs.llvmPackages_20.clang-unwrapped

packages.x86_64-linux.vivado
packages.x86_64-linux.openocd-bscanspi
Expand Down Expand Up @@ -584,8 +557,8 @@
]
++ ps.paramiko.optional-dependencies.ed25519
))
llvm_15
lld_15
pkgs.llvm_20
pkgs.lld_20
pkgs.openssh
packages.x86_64-linux.openocd-bscanspi # for the bscanspi bitstreams
];
Expand Down
Loading