### C: Example Function with Struct Pointer Dereference Source: https://github.com/etchedpixels/fuzix-compiler-kit/blob/main/Backend.md A C function example demonstrating the use of struct pointers and member access. This code serves as a basis for understanding how the compiler backend can optimize operations involving local struct pointer dereferences, as shown in the assembly examples. ```c unsigned foo(struct x *a, struct x *b) { return a->val + b->val; } ``` -------------------------------- ### Compiler Driver (cc) Usage Examples Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Examples of using the main compiler driver (cc) for various compilation tasks, including compiling to assembly, cross-compiling with optimization, using banked memory features, preprocessing only, and linking object files. ```c // Compile a single C file to assembly // cc -S -mz80 hello.c // Produces: hello.s // Cross-compile for 6502 with optimization // cc -m6502 -O2 -o program program.c helper.c // Stages: // 1. Preprocessor: program.c -> program.% // 2. Tokenizer (cc0): program.% -> program. @ // 3. Parser (cc1.6502): program. @ -> program. # // 4. Code generator (cc2.6502): program. # -> program. ^ // 5. Optimizer (copt): program. ^ -> program.s // 6. Assembler: program.s -> program.o // 7. Linker: program.o + helper.o + lib6502.a -> program // Compile for Z80 with banked memory support // cc -mz80-banked -O1 -tnone -o firmware.out firmware.c // The -mz80-banked flag enables feature bit 0 for banked memory layout // The -tnone flag disables OS-specific linking conventions // Preprocess only (view preprocessor output) // cc -E -m8080 -I../include -D__DEBUG__ source.c // Output goes to stdout showing all macro expansions and includes // Link existing object files with custom startup // cc -mz80 -o app.out crt_custom.o main.o utils.o -lmath // Uses /opt/fcc/lib/z80/lib/ for libraries and includes ``` -------------------------------- ### Bash: Fuzix Compiler Kit Command-Line Options Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Examples of using the Fuzix compiler (cc) with various command-line options for cross-compilation. This includes basic compilation, optimization levels, target selection, preprocessor directives, controlling compilation stages, linking options, and debugging flags. ```bash # Basic compilation cc -mz80 -o program.out program.c # Specify optimization level cc -m6502 -O0 program.c # No optimization (default) cc -m6502 -O1 program.c # Basic optimization cc -m6502 -O2 program.c # Standard optimization cc -m6502 -O3 program.c # Aggressive optimization cc -m6502 -Os program.c # Optimize for size # Target selection with features cc -mz80-banked-noix program.c # Z80 with banked memory, IX not available cc -mnova3-multiply program.c # Nova 3 with hardware multiply # Preprocessing options cc -m8080 -DDEBUG -D__PLATFORM__=FUZIX -Iinclude/ program.c cc -E program.c # Preprocess only # Stop at different stages cc -E program.c # Preprocess only (stdout) cc -S program.c # Compile to assembly (program.s) cc -c program.c # Compile to object (program.o) # Linking options cc -o app main.o utils.o -lmath # Link with math library cc -L/opt/libs -lfoo program.c # Add library search path cc -s program.c # Strip symbols cc -M program.c # Generate map file # Target OS selection cc -tnone program.c # Bare metal (no OS support) cc -tfuzix program.c # Fuzix OS (default) cc -tfuzixrel1 program.c # Fuzix with relocations (256-byte) cc -tfuzixrel2 program.c # Fuzix with relocations (512-byte) # Standalone compilation (no C library) cc -s -tnone program.c # No crt0, no libc # Custom code segment cc -T0x8000 program.c # Code starts at 0x8000 # Debugging and development cc -V program.c # Verbose (print each command) cc -X program.c # Keep temporary files cc -c program.c -o custom.o # Custom output name # Multi-file compilation cc -m6809 main.c utils.c io.c -o firmware.out cc -m6809 -c main.c # Compile to main.o (no link) cc -m6809 -c utils.c # Compile to utils.o (no link) cc -m6809 main.o utils.o # Link only # Cross-compilation example for embedded target # Directory structure: ``` -------------------------------- ### C: Subtree Shortcut for Custom Code Generation Handling Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Provides a mechanism to shortcut the standard tree descent for code generation, allowing custom handling of entire subtrees. It is called during tree descent and returns 1 if the subtree has been completely generated. Examples include dead code elimination and optimizing assignments with direct addressing. ```c // Complete subtree shortcut for custom handling unsigned gen_shortcut(struct node *n) { // Called during tree descent // Return 1 if entire subtree has been generated // Example: Dead code elimination if (n->flags & NORETURN && !has_side_effects(n)) { return 1; // Skip generating code for unused value } // Example: Optimize assignment with direct addressing if (n->op == T_ASSIGN) { struct node *left = n->left; struct node *right = n->right; // Both sides are "easy" - pick best order if (gen_direct(left) && gen_direct(right)) { // Generate right side first, then assign gen_load_node(right); gen_store_node(left); return 1; // Handled completely } } return 0; // Use default tree walk } ``` -------------------------------- ### C: Unary Operation Direct Handling for Stack Optimization Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Handles unary operations directly, similar to `gen_direct` but specifically for unary operators. It returns 1 if the operation can be performed without using the stack, thus optimizing code generation. Examples include negating constants at compile time and dereferencing global pointers directly. ```c // Unary operation direct handling unsigned gen_uni_direct(struct node *n) { // Like gen_direct but for unary operators // Return 1 if operation can be done without stack switch(n->op) { case T_NEGATE: if (n->right->op == T_CONSTANT) { // Negate constant at compile time printf("\tld\thl,%u\n", (unsigned)(-n->right->value)); return 1; } break; case T_DEREF: if (n->right->op == T_NAME && is_global(n->right)) { // Dereference global pointer directly printf("\tld\thl,("); gen_name(n->right); printf(")\n\tld\tl,(hl)\n\tld\th,0\n"); return 1; } break; } return 0; } ``` -------------------------------- ### C: Tree Rewriting for Architecture-Specific Patterns Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Implements tree rewriting rules to transform expression subtrees into more efficient forms specific to the target architecture. It is called bottom-up before code generation and can return a modified tree or NULL if no changes are needed. Examples include optimizing multiplication by 2 into a left shift and folding local variable references. ```c // Tree rewriting for architecture-specific patterns struct node *gen_rewrite_node(struct node *n) { // Called bottom-up before code generation // Return modified tree or NULL for no change // Example: Rewrite (x * 2) to (x << 1) if (n->op == T_STAR && n->right->op == T_CONSTANT) { unsigned long val = n->right->value; if (val == 2) { // Multiply by 2 n->op = T_LTLT; // Convert to left shift n->right->value = 1; return n; } } // Example: Fold local variable dereferences if (n->op == T_LREF && n->right->op == T_CONSTANT) { // Convert (base + offset) to single node struct node *folded = new_node(); folded->op = T_LREFOFFSET; folded->value = n->value + n->right->value; folded->type = n->type; free_node(n->right); free_node(n); return folded; } return NULL; // No rewriting needed } ``` -------------------------------- ### 8080 Assembly: Optimizing Variable Access Source: https://github.com/etchedpixels/fuzix-compiler-kit/blob/main/Backend.md Demonstrates optimization of direct variable access on the 8080 processor. It shows how to rewrite code to avoid trashing the working register (HL) when loading constants and globals, improving efficiency. This optimization is crucial for processors with limited register manipulation capabilities. ```assembly lhld,_arg1 push h lhld _arg2 pop d dad d ``` ```assembly lhld _arg1 xchg lhld _arg2 xchg dad d ``` ```assembly lhld _arg1 xchg lhld _arg2 dad d ``` -------------------------------- ### Compiler Stage 1: Tokenization (cc0) Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Details the first stage of the FCC compiler, `cc0`, which performs tokenization. It converts preprocessed C source code into a stream of 16-bit tokens and generates a symbol table for subsequent stages. Input is via stdin, output to stdout. ```c // Stage 1: Tokenization (cc0) // Input: Preprocessed C source (stdin) // Output: Token stream (stdout) + symbol table (.symtmp file) // // cc0 converts source into 16-bit tokens where identifiers are numbered // Example: "int fred = 5;" becomes tokens like [T_INT][0x8004][T_ASSIGN][T_NUMBER] // All instances of "fred" map to the same token number (e.g., 0x8004) // Symbol names are written to a side file for later use by cc2 // // Usage (internal): // cc0 .symtmp1234 < input.% > output. @ ``` -------------------------------- ### Generate Labels and Branches in C Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Functions to generate assembly labels and conditional/unconditional jump instructions. Supports branching based on the working register (HL) being zero or non-zero. No external dependencies beyond standard I/O. ```c // Label and branch generation void gen_label(const char *prefix, unsigned n) { printf("%s%u:\n", prefix, n); } void gen_jump(const char *prefix, unsigned n) { printf("\tjp\t%s%u\n", prefix, n); } void gen_jtrue(const char *prefix, unsigned n) { // Branch if working register (HL) is non-zero printf("\tld\ta,h\n\tor\tl\n"); // Test if HL == 0 printf("\tjr\tnz,%s%u\n", prefix, n); // Jump if not zero } void gen_jfalse(const char *prefix, unsigned n) { printf("\tld\ta,h\n\tor\tl\n"); printf("\tjr\tz,%s%u\n", prefix, n); } ``` -------------------------------- ### Compiler Stage 2: Parsing (cc1.{cpu}) Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Describes the second stage, `cc1.{cpu}`, responsible for parsing. It takes the token stream from `cc0` and generates expression trees. This stage is CPU-specific and focuses on memory efficiency by packing type information. ```c // Stage 2: Parsing (cc1.{cpu}) // Input: Token stream (stdin) // Output: Expression trees with structural headers (stdout) // Parameters: CPU code, feature flags // // cc1 performs recursive descent parsing and generates expression trees // Trees are per-statement; no whole-function or whole-program optimization // Type information is packed into 16-bit values to save memory // // Usage (internal): // cc1.z80 80 0 < input. @ > output. # // // Expression tree format example for "a = b + c * 2": // [HEADER: ASSIGN] // [TREE: left=NAME(a), right=ADD, ADD.left=NAME(b), ADD.right=MUL(NAME(c),CONST(2))] // [FOOTER] ``` -------------------------------- ### Implement Switch Statements in C Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Functions for generating assembly code for switch statements, including a jump table lookup mechanism. Requires a helper function `__switch_helper` and specific label formats for cases and defaults. Outputs assembly directives for jump tables. ```c // Switch statement support void gen_switch(unsigned n, unsigned type) { // Generate jump table lookup printf("\tld\tde,__switch%u\n", n); printf("\tcall\t__switch_helper\n"); // Helper searches table } void gen_case_label(unsigned tag, unsigned entry) { printf("__case_%u_%u:\n", tag, entry); } void gen_case_data(unsigned tag, unsigned entry) { // Entry in jump table: [value] [address] printf("\t.word\t%u\n", entry); printf("\t.word\t__case_%u_%u\n", tag, entry); } ``` -------------------------------- ### Optional Stage: Optimization (copt) Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Describes the optional optimization stage, `copt`, which takes assembly code as input and outputs optimized assembly. It employs CPU-specific peephole optimization rules to reduce code size and improve performance. ```c // Optional Stage: Optimization (copt) // Input: Assembly code (stdin) // Output: Optimized assembly (stdout) // Uses CPU-specific peephole optimization rules // // copt /opt/fcc/lib/rules.z80 < input. ^ > output.s // // Example optimization rules from rules.z80: // Pattern: ld hl,%1 / push hl / pop de // Replace: ld de,%1 // Saves 2 bytes and 10 clock cycles ``` -------------------------------- ### Generate Static Data Definitions in C Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Functions to define static data in assembly, including labels, alignment, and values of different types (byte, word, long). Supports reserving uninitialized space. Uses assembly directives like `.data`, `.align`, `.byte`, `.word`, `.long`, and `.ds`. ```c // Static data generation void gen_data_label(const char *name, unsigned align) { printf("\t.data\n"); if (align > 1) printf("\t.align\t%u\n", align); printf("_%s:\n", name); } void gen_value(unsigned type, unsigned long value) { switch(type & TMASK) { case CCHAR: printf("\t.byte\t%u\n", (unsigned)value & 0xFF); break; case CSHORT: case PTR: printf("\t.word\t%u\n", (unsigned)value & 0xFFFF); break; case CLONG: printf("\t.long\t%lu\n", value); break; } } void gen_space(unsigned bytes) { printf("\t.ds\t%u\n", bytes); // Reserve space } ``` -------------------------------- ### C: Generate Runtime Helper Calls Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Functions for generating calls to runtime library helper functions in C. These functions handle different scenarios, including signed/unsigned operations and generic calls with explicit type and size. They are crucial for performing complex operations on resource-constrained 8-bit CPUs. ```c // Helper call generation void helper(struct node *n, const char *name) { // Generate call to runtime helper // Working register contains right operand // Stack top contains left operand printf("\tcall\t%s\n", name); } void helper_s(struct node *n, const char *name) { // Helper for signed operations (uses signed library function) if (n->type & UNSIGNED) printf("\tcall\t%su\n", name); // Unsigned variant else printf("\tcall\t%ss\n", name); // Signed variant } void do_helper(struct node *n, const char *name, unsigned t, unsigned s) { // Generic helper with explicit type and size printf("\tcall\t%s", name); if (t) printf("_%c", type_suffix(t)); if (s) printf("%u", s); printf("\n"); } // Example: Long arithmetic on 8-bit CPU // Expression: long_a + long_b // Generated code: // ld hl,(long_a) ; Load low word of a // ld de,(long_a+2) ; Load high word of a // push de // push hl ; Stack left operand (4 bytes) // ld hl,(long_b) ; Load low word of b // ld de,(long_b+2) ; Load high word of b // call __addl ; Helper does 32-bit add // ; Result returned in DEHL // Common helper functions in support library: // __addl, __subl, __mull, __divl - Long arithmetic // __adds, __subs, __muls, __divs - Signed int operations // __addu, __subu, __mulu, __divu - Unsigned int operations // __lshl, __lsrl, __asrl - Long shifts // __eq, __ne, __lt, __gt, __le, __ge - Comparisons // __bool - Convert to boolean // __switchl - Long switch lookup // __cast - Type conversions // Helper declarations (typically in support library header) // extern uint32_t __addl(uint32_t left, uint32_t right); // extern int16_t __divs(int16_t left, int16_t right); // extern uint16_t __divu(uint16_t left, uint16_t right); ``` -------------------------------- ### Compiler Stage 3: Code Generation (cc2.{cpu}) Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Details the third stage, `cc2.{cpu}`, which generates target assembly code from expression trees. It supports architecture-specific optimizations through tree rewriting and utilizes helper functions for complex operations. Input is via stdin, output to stdout. ```c // Stage 3: Code Generation (cc2.{cpu}) // Input: Expression trees (stdin) // Output: Assembly code (stdout) // Parameters: Symbol table file, CPU code, optimization level, feature flags // // cc2 walks expression trees and generates target assembly // Supports tree rewriting for architecture-specific optimizations // Uses helper functions for complex operations (long arithmetic, etc.) // // Usage (internal): // cc2.z80 .symtmp1234 80 2 0 < input. # > output.s // // Generated assembly includes: // - Function prologue/epilogue with stack frame setup // - Expression evaluation (typically stack-based) // - Helper calls for operations the backend doesn't optimize // - Jump tables for switch statements ``` -------------------------------- ### Z80 Target Configuration: Data Types and ABI Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Defines Z80-specific data type sizes, alignment requirements, argument passing rules, type remapping for hardware limitations (like float), and register variable eligibility. It also includes comments outlining the Z80 function call ABI. ```c // Target configuration (target-z80.c example) unsigned target_ptr = 2; // Pointers are 2 bytes unsigned target_sizeof(unsigned t) { // Return size in bytes for type switch(t & TMASK) { case CCHAR: return 1; case CSHORT: return 2; case CINT: return 2; // int is 16-bit on most 8-bit targets case CLONG: return 4; case FLOAT: return 4; case DOUBLE: return 4; // No 64-bit double on these platforms case PTR: return 2; default: return 0; } } unsigned target_alignof(unsigned t, unsigned storage) { // Return alignment requirement if (storage == S_REGISTER) return 1; // Registers have no alignment switch(t & TMASK) { case CLONG: case DOUBLE: return 2; // Long and double require 2-byte alignment default: return 1; // Everything else is byte-aligned } } unsigned target_argsize(unsigned t) { // Arguments are passed on stack, rounded up to word size unsigned size = target_sizeof(t); if (size == 1) return 2; // Promote chars to int return size; } // Platform type remapping unsigned target_type_remap(unsigned t) { // Remap types not supported in hardware // Example: No native float, remap to long if ((t & TMASK) == FLOAT) { return (t & ~TMASK) | CLONG; } return t; } // Register variable support unsigned target_register(unsigned t, unsigned storage) { // Return 1 if this type can be a register variable if (storage != S_REGISTER) return 0; // Z80 can use BC, IX, IY as register variables switch(t & TMASK) { case CCHAR: case CSHORT: case PTR: return 1; // These fit in 16-bit registers default: return 0; // Long and double too large } } // Example target-specific ABI decisions // // Function call on Z80: // - Arguments pushed right-to-left // - Caller cleans stack // - Return value in HL (16-bit) or HLDE (32-bit) // - BC, IX, IY can be register variables (callee-saved) // - DE, HL are scratch registers // // void gen_frame(unsigned size, unsigned argsize) { // // Set up stack frame // printf("\tpush\tix\n"); // Save frame pointer // printf("\tld\tix,0\n"); // printf("\tadd\tix,sp\n"); // IX = frame pointer // if (size > 0) { // printf("\tld\thl,-%u\n", size); // printf("\tadd\tix,sp\n"); // Incorrect - should be add hl,sp // printf("\tld\tsp,hl\n"); // Allocate locals // } // } ``` -------------------------------- ### Assembly: Z80 Implementation of __addl Helper Source: https://context7.com/etchedpixels/fuzix-compiler-kit/llms.txt Assembly code for the Z80 processor implementing the `__addl` helper function, which performs a 32-bit addition. This snippet demonstrates low-level operations for handling long arithmetic on an 8-bit CPU, including stack manipulation and register usage. ```assembly ; Assembly implementation example (__addl for Z80): __addl: pop bc ; Return address pop de ; Left low word pop hl ; Left high word push hl push de push bc ; Restore return address add hl,sp ld bc,4 add hl,bc ; HL = &right on stack ld c,(hl) inc hl ld b,(hl) ; BC = right low word inc hl ld e,(hl) inc hl ld d,(hl) ; DE = right high word pop hl ; Left high word again ex de,hl add hl,de ; Add high words ex de,hl ; DE = high result pop hl ; Left low word again add hl,bc ; Add low words ret c ; Carry into high word inc de ret ``` -------------------------------- ### 65C816 Assembly: Optimized Addition with Local Variables Source: https://github.com/etchedpixels/fuzix-compiler-kit/blob/main/Backend.md Illustrates optimized arithmetic operations on the 65C816 processor, specifically handling addition involving local variables and struct member access. It leverages the processor's ability to directly access memory addresses relative to registers (Y) for efficient data manipulation. ```assembly lda _arg1 clc adc _arg2 ``` ```assembly lda arg1,y clc adc arg2,y ``` ```assembly ldx arg1,y lda 2,x ldx arg2,y clc adc 2,x ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.