Hone logo
Hone
Problems

Generating LLVM IR for a Simple Arithmetic Expression in Rust

This challenge focuses on the fundamental process of generating Low-Level Virtual Machine (LLVM) Intermediate Representation (IR) for a given input. You will create a Rust program that takes a simple arithmetic expression as input and outputs its equivalent LLVM IR code. This is a crucial step in understanding compiler design and how high-level code is translated into a form that can be optimized and compiled for various architectures.

Problem Description

Your task is to implement a Rust function that accepts a string representing a basic arithmetic expression involving addition and subtraction of integers. The function should parse this expression and generate LLVM IR code that, when compiled, would perform the calculation described by the expression.

The LLVM IR should adhere to the following:

  • Function Definition: A single function named calculate should be defined. This function should take no arguments and return an i32 (32-bit integer).
  • Basic Blocks: The IR should utilize basic blocks effectively, even for this simple case.
  • Arithmetic Operations: Implement LLVM IR instructions for addition (add) and subtraction (sub).
  • Integer Literals: Handle integer literals directly within the IR.
  • Return Value: The function must conclude with a ret instruction.

You are not expected to perform complex parsing (like operator precedence or parentheses handling beyond simple left-to-right evaluation) for this challenge. Focus on translating a linear sequence of operations into LLVM IR.

Examples

Example 1:

Input: 10 + 5

Output:

; ModuleID = 'my_module'
source_filename = "my_module"

define i32 @calculate() {
entry:
  %tmp0 = add i32 10, 5
  ret i32 %tmp0
}

Explanation: The input 10 + 5 is translated into an LLVM IR add instruction. The result is then returned.

Example 2:

Input: 20 - 7 + 3

Output:

; ModuleID = 'my_module'
source_filename = "my_module"

define i32 @calculate() {
entry:
  %tmp0 = sub i32 20, 7
  %tmp1 = add i32 %tmp0, 3
  ret i32 %tmp1
}

Explanation: The expression is evaluated left-to-right. 20 - 7 is performed first, and its result is then added to 3. Temporary variables (%tmp0, %tmp1) are used to store intermediate results.

Example 3:

Input: 5

Output:

; ModuleID = 'my_module'
source_filename = "my_module"

define i32 @calculate() {
entry:
  ret i32 5
}

Explanation: A single integer literal is directly returned.

Constraints

  • The input expression will only contain non-negative integer literals, the + operator, and the - operator.
  • Whitespace will be used as a separator between numbers and operators.
  • The expression will always be valid and represent a linear sequence of operations (no parentheses or complex precedence rules).
  • Intermediate results and the final result will fit within an i32.
  • The generated LLVM IR should be syntactically correct according to the LLVM IR reference.

Notes

  • You will need to use an LLVM Rust binding crate (e.g., inkwell or llvm-sys) to construct the LLVM IR programmatically.
  • Consider how to parse the input string into a sequence of numbers and operators.
  • Think about how to manage temporary values (registers) in LLVM IR for intermediate calculations.
  • The goal is to produce a human-readable LLVM IR string, not to execute it. The output should closely resemble the examples provided.
  • The ModuleID and source_filename can be set to any reasonable default, like "my_module".
Loading editor...
rust