For background information on the topic as a whole, scroll to the end of this page.
Available Project Proposals
If you are interested in the general topic of Programming Languages, or if have your own project idea related to the topic, please contact us directly. Alternatively, you can also work on one of the following concrete project proposals:
Compiler Optimizations in Rust for GPU Targets (Georgiana Caltais, Niek Aukes) Rust is a powerful systems programming language known for its safety, speed, and concurrency features. While Rust has traditionally been used for CPU programming, there is growing interest in leveraging its capabilities for GPU programming as well. Last year, we developed a Rust compiler variant capable of compiling Rust code for both CPU and GPU in a single compilation step (https://essay.utwente.nl/100981/).
A significant limitation however, is the lack of optimizations tailored specifically for GPU targets. Benchmarks made on similar code in Cuda C++ and Rust showed that the Rust code is significantly slower, up to 25x! Inspecting the bytecode generated revealed that the NVIDIA compilers are not able to optimize the Rust code as well as the Cuda C++ code.
In this project, we aim to improve the performance of Rust code targeting GPUs by implementing compiler optimizations specifically designed for GPU targets. This could involve optimizations such as loop unrolling, and memory coalescing, among others. By enhancing the Rust compiler's ability to generate efficient GPU code, we hope to close the performance gap with traditional GPU programming languages and make Rust a more competitive choice for GPU programming.
Context-dependent language items for Rust (Georgiana Caltais, Niek Aukes) Rust is rapidly becoming the go-to language for systems programming, powering everything from embedded devices to high-performance computing. Last year, we developed a Rust compiler variant capable of compiling Rust code for both CPU and GPU in a single compilation step (https://essay.utwente.nl/100981/). This approach enables improved interoperability between CPU and GPU code, a feature highly desirable in fields like scientific computing, game development, and AI.
However, a major limitation of this prototype is its lack of support for essential Rust features beyond the core language. Fundamental constructs like ranges, iterators, and panic handling are either missing or unstable, often causing the compiler to crash.
This project aims to solve that problem by introducing a context-dependent language item system. This system would allow the compiler to define and adapt language items based on the context in which they are used. With this approach, GPU-specific language items could coexist with standard Rust implementations for CPU contexts, greatly expanding the capabilities of the compiler.
If you’re excited about compiler design and Rust’s inner workings, this project may be for you!
Design Your Own PL (Peter Lammich) Design your own programming language, trying to combine fancy features from recent modern programming languages in a reasonable way. Use LLVM as back-end, to get all standard optimizations and code-generation (almost) for free.
Language Workbenches Comparison (Vadim Zaytsev) Domain Specific Languages (DSLs) are languages that aim to either make programming more accessible for end-users by simplifying the constructs within the language, or languages that make specific tasks easier to perform for regular programmers.
There are many ways to implement DSLs using tools called language workbenches. Some of these language workbenches are best suited for implementing textual DSLs (Rascal), others are better suited implementing domain specific modelling languages (Eclipse Sirius), and some can be used to create hybrid languages (MPS).
In this project you are tasked with implementing a subset of the DOT language (the language of Graphviz) as a domain specific (modelling) language using several language workbenches, and you will be comparing the pros and cons of using each workbench.
Platform independent LLVM IR (Peter Lammich) Modify the LLVM Intermediate Representation to be platform independent.
Motivation and Problem Description:
The LLVM project provides an infrastructure to build compilers. In particular, it defines an easy to use intermediate representation (LLVM-IR), that serves as the interface between compiler front ends and back ends. It comes in a binary and textual syntax. This makes developing new compilers easy, as all the hard optimization and machine code generation work is done by the backend, and a new compiler only needs to generate (unoptimized) IR. However, the LLVM-IR is platform dependent and generating it depends on using the LLVM libraries, which restricts the implementation language for your compiler to those that have (well-maintained) bindings for these libraries.
Example: Unions
A union type overlays several types in memory. It is an important low-level concept required for the implementation of many high-level features (e.g. Haskell's algebraic datatypes or C++'s variants).
To implement a union datatype in LLVM-IR (e.g. union { i32, float, i8* }), you have to define a type whose size equals the biggest member type. Which one that is can depend on the platform, e.g., the size of a pointer. Using the LLVM library, it's easy to obtain the size of a type, and define, e.g., a byte array with that many elements:
%t = type [ 4 x i8 ]
However, LLVM-IR has no syntax to symbolically express this size, e.g., there is nothing like:
%t = type [ max_sizeof(i32,float,i8*) x i8 ]
However, the latter would still be correct on any platform (while the former only works for platforms with 32 bit pointers). Moreover, without bindings to LLVM's libraries, a correct size computation is difficult and error prone (it depends on platform ABI, alignment, etc).
Your Tasks
- Identify platform or library dependencies in LLVM-IR
- Propose modifications to make LLVM-IR (more) platform and library independent
- Implement and evaluate a prototype
Interested? Drop me an email: p.lammich@utwente.nl
Interested in something similar, having your own ideas? Even better!: p.lammich@utwente.nl
ContacT
Background
There are many programming languages out there, with different features for solving different problems. Most of them can be roughly categorized in what paradigms, i.e., approaches to programming, they support. Three well-known paradigms are:
- imperative, where a program describes how to change the state of objects (e.g. variables). For example, C and Java are imperative languages, and Python supports, among others, imperative programming.
- functional, where a program is described as a (mathematical) function. Haskell is a typical example.
- declarative describes the desired result, but no direct way to compute it. An example is the SQL database query language.
Note, however, that many programming languages support more than one paradigm, or are somewhere in between. For example, Python also supports functional programming, and C++ and Java have evolved from purely imperative languages to also support functional features, like lambda abstractions. An overview of many paradigms and languages can be found in this video, which is based on Peter van Roy's overview.
Alternatively, depending on their application domain, programming languages can be categorized as:
- domain-specific languages (DSL), that are specialized to a particular application domain. Examples include HTML (for Web applications), SQL (for data management), Maven and Gradle (as build automation tools), MATLAB (for numerical computation and simulation), Lex and YACC (as lexical analysers and parser generators), and Frenetic (for programming software-defined networks), for instance.
- general-purpose languages (GPL), that are broadly applicable across domains. Examples include C, Java, PHP and Python.
In this topic, we cover questions about programming languages, including their design, features, and implementations. Typical projects in this topic
- add new features to an existing programming language
- improve an existing programming language implementation
- implement a new programming language from scratch
- compare different programming languages
Prerequisites
- Programming experience, ideally with more than one language
Related Modules
- Programming Paradigms (functional, concurrent and logic programming + compiler construction)
- Discrete Structures and Algorithms (automata and graph algorithms, semantics)