Skip to content
Open
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
28 changes: 28 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM rust:latest

# Install build dependencies
RUN apt-get update && apt-get install -y \
build-essential \
pkg-config \
gcc-aarch64-linux-gnu \
gcc-riscv64-linux-gnu \
gcc-arm-linux-gnueabihf \
libc6-dev \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy the source code
COPY . .

# Build the ccc compiler in release mode
RUN cargo build --release

# Create a working directory for files to compile
WORKDIR /workspace

# Set the default binary to ccc (x86-64)
ENTRYPOINT ["/app/target/release/ccc"]

# Default command: show usage
CMD ["--help"]
112 changes: 112 additions & 0 deletions ccc-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/bin/bash

set -e

# Parse arguments
if [ "$1" != "--run" ]; then
echo "Usage: $0 --run <filename> [ccc arguments...]"
echo ""
echo "Example:"
echo " $0 --run hello.c -o hello"
echo " $0 --run test.c"
exit 1
fi

shift # remove --run

if [ -z "$1" ]; then
echo "Error: filename required"
echo "Usage: $0 --run <filename> [ccc arguments...]"
exit 1
fi

filename="$1"
shift # remove filename

# Check if file exists
if [ ! -f "$filename" ]; then
echo "Error: File '$filename' not found"
exit 1
fi

# Get absolute path
abs_filename=$(cd "$(dirname "$filename")" && pwd)/$(basename "$filename")
work_dir=$(dirname "$abs_filename")
file_basename=$(basename "$filename")

# Determine output filename
output_name=""
remaining_args=()
prev_arg=""
for arg in "$@"; do
if [ "$prev_arg" = "-o" ]; then
output_name="$arg"
else
remaining_args+=("$arg")
fi
prev_arg="$arg"
done

# If no -o flag, use filename without extension
if [ -z "$output_name" ]; then
output_name="${file_basename%.c}"
fi

# Get the directory where the script is located
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Build the Docker image if it doesn't exist
image_name="ccc-compiler"
if ! docker image inspect "$image_name" > /dev/null 2>&1; then
echo "Building Docker image: $image_name"
docker build -t "$image_name" "$script_dir"
fi

# Build extra args string (shell-escaped)
extra_args=""
for arg in "${remaining_args[@]}"; do
extra_args+=" $(printf '%q' "$arg")"
done

# Compile the file inside the container with dynamic include paths
echo "Compiling $filename with ccc in Docker..."
docker run --rm \
-v "$work_dir:/workspace" \
--entrypoint /bin/sh \
-e OUTPUT_NAME="$output_name" \
-e FILE_BASENAME="$file_basename" \
-e EXTRA_ARGS="$extra_args" \
"$image_name" \
-lc '
set -e
ARCH=$(gcc -dumpmachine)
INCDIR=$(gcc -print-file-name=include)
if echo "$ARCH" | grep -q "aarch64"; then
CCC=/app/target/release/ccc-arm
else
CCC=/app/target/release/ccc
fi

"$CCC" \
-isystem /usr/include \
-isystem "/usr/include/${ARCH}" \
-isystem "${INCDIR}" \
-L "/usr/lib/${ARCH}" \
-L "/lib/${ARCH}" \
-lc \
-o "/workspace/${OUTPUT_NAME}" \
"/workspace/${FILE_BASENAME}" ${EXTRA_ARGS}
'

echo ""
echo "Running compiled binary..."
docker run --rm \
-v "$work_dir:/workspace" \
--entrypoint /bin/sh \
-e OUTPUT_NAME="$output_name" \
"$image_name" \
-lc '
ARCH=$(gcc -dumpmachine)
export LD_LIBRARY_PATH="/lib/${ARCH}:/usr/lib/${ARCH}:${LD_LIBRARY_PATH}"
exec "/workspace/${OUTPUT_NAME}"
'
6 changes: 3 additions & 3 deletions src/backend/arm/assembler/encoder/load_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub(crate) fn encode_ldr_str(operands: &[Operand], is_load: bool, size: u32, is_
// Check if offset is aligned and fits in 12-bit unsigned field
let abs_offset = *offset as u64;
let align = 1u64 << shift;
if *offset >= 0 && abs_offset.is_multiple_of(align) {
if *offset >= 0 && crate::common::is_multiple_of::is_multiple_of(abs_offset, align) {
let imm12 = (abs_offset / align) as u32;
if imm12 < 4096 {
// Unsigned offset form: size 111 V 01 opc imm12 Rn Rt
Expand Down Expand Up @@ -321,7 +321,7 @@ pub(crate) fn encode_ldrsw(operands: &[Operand]) -> Result<EncodeResult, String>
// LDRSW: size=10 111 V=0 01 opc=10 -> unsigned offset
// Actually: 10 111 0 01 10 imm12 Rn Rt
let abs_offset = *offset as u64;
if *offset >= 0 && abs_offset.is_multiple_of(4) {
if *offset >= 0 && crate::common::is_multiple_of::is_multiple_of(abs_offset, 4) {
let imm12 = (abs_offset / 4) as u32;
if imm12 < 4096 {
let word = ((0b10 << 30) | (0b111 << 27)) | (0b01 << 24) | (0b10 << 22)
Expand Down Expand Up @@ -393,7 +393,7 @@ pub(crate) fn encode_ldrs(operands: &[Operand], size: u32) -> Result<EncodeResul
let shift = size;
let abs_offset = *offset as u64;
let align = 1u64 << shift;
if *offset >= 0 && abs_offset.is_multiple_of(align) {
if *offset >= 0 && crate::common::is_multiple_of::is_multiple_of(abs_offset, align) {
let imm12 = (abs_offset / align) as u32;
if imm12 < 4096 {
let word = ((size << 30) | (0b111 << 27)) | (0b01 << 24) | (opc << 22)
Expand Down
2 changes: 1 addition & 1 deletion src/backend/arm/codegen/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1427,7 +1427,7 @@ impl ArmCodegen {
for (i, _) in args.iter().enumerate() {
match arg_classes[i] {
CallArgClass::I128RegPair { .. } => {
if !int_reg_idx.is_multiple_of(2) { int_reg_idx += 1; }
if !crate::common::is_multiple_of::is_multiple_of(int_reg_idx, 2) { int_reg_idx += 1; }
int_reg_idx += 2;
}
CallArgClass::StructByValReg { size, .. } => {
Expand Down
6 changes: 3 additions & 3 deletions src/backend/call_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ fn classify_args_core(
// Note: ARM AAPCS64 does NOT require even-aligned pairs for composites.
if regs_needed == 2 && config.align_struct_pairs {
let struct_align = info.struct_align.unwrap_or(slot_size);
if struct_align > slot_size && !int_idx.is_multiple_of(2) {
if struct_align > slot_size && (int_idx % 2 == 1) {
int_idx += 1; // skip to even register
}
}
Expand All @@ -503,7 +503,7 @@ fn classify_args_core(
result.push(CoreArgClass::LargeStructStack { size });
}
} else if info.is_i128 {
if config.align_i128_pairs && !int_idx.is_multiple_of(2) {
if config.align_i128_pairs && !crate::common::is_multiple_of::is_multiple_of(int_idx, 2) {
int_idx += 1;
}
if int_idx + 1 < config.max_int_regs {
Expand All @@ -522,7 +522,7 @@ fn classify_args_core(
result.push(CoreArgClass::F128Stack);
}
} else if config.f128_in_gp_pairs {
if config.align_i128_pairs && !int_idx.is_multiple_of(2) {
if config.align_i128_pairs && !crate::common::is_multiple_of::is_multiple_of(int_idx, 2) {
int_idx += 1;
}
if int_idx + 1 < config.max_int_regs {
Expand Down
2 changes: 1 addition & 1 deletion src/backend/riscv/linker/emit_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ pub fn emit_shared_library(
0, shstrtab_file_offset, shstrtab_data.len() as u64, 0, 0, 1, 0));

// Write section headers
while !elf.len().is_multiple_of(8) { elf.push(0); }
while !crate::common::is_multiple_of::is_multiple_of(elf.len(), 8) { elf.push(0); }
let shdr_offset = elf.len() as u64;
let shdr_count = section_headers.len();

Expand Down
4 changes: 2 additions & 2 deletions src/backend/x86/codegen/calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl X86Codegen {

pub(super) fn emit_call_stack_args_impl(&mut self, args: &[Operand], arg_classes: &[CallArgClass],
_arg_types: &[IrType], stack_arg_space: usize, _fptr_spill: usize, _f128_temp_space: usize) -> i64 {
let need_align_pad = !stack_arg_space.is_multiple_of(16);
let need_align_pad = !crate::common::is_multiple_of::is_multiple_of(stack_arg_space, 16);
if need_align_pad {
self.state.emit(" subq $8, %rsp");
}
Expand Down Expand Up @@ -265,7 +265,7 @@ impl X86Codegen {
}

pub(super) fn emit_call_cleanup_impl(&mut self, stack_arg_space: usize, _f128_temp_space: usize, _indirect: bool) {
let need_align_pad = !stack_arg_space.is_multiple_of(16);
let need_align_pad = !crate::common::is_multiple_of::is_multiple_of(stack_arg_space, 16);
let total_cleanup = stack_arg_space + if need_align_pad { 8 } else { 0 };
if total_cleanup > 0 {
self.state.out.emit_instr_imm_reg(" addq", total_cleanup as i64, "rsp");
Expand Down
4 changes: 2 additions & 2 deletions src/backend/x86/linker/emit_exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1080,12 +1080,12 @@ pub(super) fn emit_executable(
sh_count += 1;

// Align and append .shstrtab data
while !out.len().is_multiple_of(8) { out.push(0); }
while !crate::common::is_multiple_of::is_multiple_of(out.len(), 8) { out.push(0); }
let shstrtab_data_offset = out.len() as u64;
out.extend_from_slice(&shstrtab);

// Align section header table to 8 bytes
while !out.len().is_multiple_of(8) { out.push(0); }
while !crate::common::is_multiple_of::is_multiple_of(out.len(), 8) { out.push(0); }
let shdr_offset = out.len() as u64;

// Write section headers
Expand Down
4 changes: 2 additions & 2 deletions src/backend/x86/linker/emit_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1085,12 +1085,12 @@ pub(super) fn emit_shared_library(
sh_count += 1;

// Align and append .shstrtab data
while !out.len().is_multiple_of(8) { out.push(0); }
while !crate::common::is_multiple_of::is_multiple_of(out.len(), 8) { out.push(0); }
let shstrtab_data_offset = out.len() as u64;
out.extend_from_slice(&shstrtab);

// Align section header table to 8 bytes
while !out.len().is_multiple_of(8) { out.push(0); }
while !crate::common::is_multiple_of::is_multiple_of(out.len(), 8) { out.push(0); }
let shdr_offset = out.len() as u64;

// Write section headers
Expand Down
3 changes: 3 additions & 0 deletions src/common/is_multiple_of.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn is_multiple_of<T: std::ops::Rem<Output = T> + PartialEq + From<u8> + Copy>(value: T, divisor: T) -> bool {
divisor != T::from(0) && value % divisor == T::from(0)
}
1 change: 1 addition & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ pub(crate) mod symbol_table;
pub(crate) mod temp_files;
pub(crate) mod type_builder;
pub(crate) mod types;
pub(crate) mod is_multiple_of;