Friday, March 14, 2025

Fifth Posting: LAB 3

 In this lab  we are making a "program". That means that we have a total freedom of what we can write on the 6502 emulator and write about it on blog.

As my hobby is a video game i went on decided to create a game that might be a bit interesting. As soon as i saw this lab's topic i thought of snake game, the game that everyone knows how to play.

But just making the snake game might be a bit boring, i want to extend this game into something more challenging as an extra.

So this is my basic idea:
So lets make an snake game and i believe  that should be good enough to fulfill all the requirements for the Lab so lets do that and maybe time to time we can extend this to something more fun....


Making muti-dimensional snake game where you play one snake with just normal arrow movement.

and at the same-time you play second snake in same screen??? But lets complete basic snake game first.


The basic idea is there but it will be more developed as I progress through out this lab. So lets dive into make our first snake.

Before we jump on making the snake game i guess there are a lot of things that we might need to think about

    - pixeled color location should be move-able when ever we press movement keys (as its changing locations as we press movement keys)

    - As the snake "eats" the target pixel then the original move-able pixel increase in length.

    - And this length should be also moving towards the direction that is following with movement key. So there should be head and tail.

    - Some of the movement should not be done. for an example in snake game the snake cannot move opposite direction right away in same row or column. It usually takes a full cycle of going right,down,left or left,right,right or right down or left down and so on.. There are many ways to go to opposite direction and we have to figure out what can be the direct reaction(output) when the condition is not met.

 I guess those are pretty much it that we might have to consider prior to creating one when it comes to "making game" so now let dive into coding this.


So first i believe that we nee the snake, since we have black back ground ready as default why don't we start with three dots



This is great! Now we can see the three dots on the top left of the emulator
LDX #$00 initializes X register to 0
Then inside of DrawLoop we Load our color, LDA #$FF
Then we increment X with INC
CPX #$03 to comp02
are Xposition to 3
Then if X is not 3 yet, loop back and write more pixels.

So now we can see that the white pixels are wirtten on ($FF) $0200, $0201, $02


Now we see that we have three dots, what could be the next?
Maybe making the pixles moveable with our keyboard?
When we are moving those we have to think about few things
-    We are not making it as "you have to continously press the moving key, pressing once will move the "snake"
-    We are moving whole pixels, not one or two minimum three and maximum as much as player stacks the target "apple"
-   Our moving key for this snake will be W,A,S,D



So now that we have displayed thre white pixels on the screen, lets start bringing them to life by introducting movement. The idea is to simulate a "snake" moving across the screen. At this stage, the snake moves automatically from left to right.

snakeX: .res 1      ; reserve 1 byte for snakeX
snakeY: .res 1      ; reserve 1 byte for snakeY
offset: .res 1      ; reserve 1 byte for offset

Start:
    LDA #$00
    STA snakeX
    STA snakeY

loop:
    JSR clearSnake
    INC snakeX
    JSR drawSnake
    JSR delay
    JMP loop

clearSnake:
    LDX snakeX
    LDY #$00
clearLoop:
    LDA #$00
    STA $0200,X
    INX
    INY
    CPY #$03
    BNE clearLoop
    RTS

drawSnake:
    LDX snakeX
    LDY #$00
drawLoop:
    LDA #$FF
    STA $0200,X
    INX
    INY
    CPY #$03
    BNE drawLoop
    RTS

delay:
    LDX #$FF
delayLoop:
    DEX
    BNE delayLoop
    RTS

    BRK



in here we enhanced our simple program from displaying just three pixels to animating basic horizontal movement.
Initialization: we have defined two variables snakeX, snakeY to track the snake's position and one temp vars offset to help calculate screen addresses.
initially set snake's starting position at the top left corner of the screen (0,0)

Main Loop: erase three pixels that is considered as snake's previous position by writing black as well ($00) and move snake by incrementing snakeXposition by one, moving the snake to the right. And draw three consecutive white pixels $FF starting from new snake's horizontal position and delay to make it a bit visible.

Next we implement basic movement with wasd, make sure to increase speed this time for making smoother movements.

define snakeHeadL     $10 ; low byte screen addr
define snakeHeadH     $11 ; high byte screen addr
define snakeBodyStart $12 ; first body segment (2 segments total)
define snakeDirection $02
define movingUp       1
define movingRight    2
define movingDown     4
define movingLeft     8

define ASCII_w        $77
define ASCII_a        $61
define ASCII_s        $73
define ASCII_d        $64

define sysLastKey     $ff
define SCREEN         $0200

  jsr initSnake

mainLoop:
  jsr readKeys
  jsr updateSnake
  jsr clearScreen
  jsr drawSnake
  jsr delay
  jmp mainLoop

initSnake:
  lda #movingRight
  sta snakeDirection

  lda #$00
  sta snakeHeadL
  lda #$03
  sta snakeHeadH

  ; body segment positions (behind head initially)
  lda #$1F
  sta $12       ; segment 1 low
  lda #$02
  sta $13       ; segment 1 high

  lda #$1E
  sta $14       ; segment 2 low
  lda #$02
  sta $15       ; segment 2 high
  rts

readKeys:
  lda sysLastKey
  cmp #ASCII_w
  beq upKey
  cmp #ASCII_d
  beq rightKey
  cmp #ASCII_s
  beq downKey
  cmp #ASCII_a
  beq leftKey
  rts

upKey:
  lda #movingDown
  bit snakeDirection
  bne illegalMove
  lda #movingUp
  sta snakeDirection
  rts

rightKey:
  lda #movingLeft
  bit snakeDirection
  bne illegalMove
  lda #movingRight
  sta snakeDirection
  rts

downKey:
  lda #movingUp
  bit snakeDirection
  bne illegalMove
  lda #movingDown
  sta snakeDirection
  rts

leftKey:
  lda #movingRight
  bit snakeDirection
  bne illegalMove
  lda #movingLeft
  sta snakeDirection
  rts

illegalMove:
  rts

updateSnake:
; shift body positions first (segments follow head)
  lda $14
  sta $12
  lda $15
  sta $13

  lda snakeHeadL
  sta $14
  lda snakeHeadH
  sta $15

; then update head based on direction
  lda snakeDirection
  lsr
  bcs up
  lsr
  bcs right
  lsr
  bcs down
  lsr
  bcs left
  rts

up:
  lda snakeHeadL
  sec
  sbc #$20
  sta snakeHeadL
  bcc upwrap
  rts
upwrap:
  dec snakeHeadH
  lda snakeHeadH
  cmp #$02
  bcc setBottom
  rts
setBottom:
  lda #$05
  sta snakeHeadH
  rts

right:
  inc snakeHeadL
  lda snakeHeadL
  and #$1f
  beq wrapRight
  rts
wrapRight:
  sec
  lda snakeHeadL
  sbc #$20
  sta snakeHeadL
  inc snakeHeadH
  lda snakeHeadH
  cmp #$06
  bne noWrapRight
  lda #$02
  sta snakeHeadH
noWrapRight:
  rts

down:
  lda snakeHeadL
  clc
  adc #$20
  sta snakeHeadL
  bcs downwrap
  rts
downwrap:
  inc snakeHeadH
  lda snakeHeadH
  cmp #$06
  bne noWrapDown
  lda #$02
  sta snakeHeadH
noWrapDown:
  rts

left:
  dec snakeHeadL
  lda snakeHeadL
  and #$1f
  cmp #$1f
  beq leftwrap
  rts
leftwrap:
  dec snakeHeadH
  lda snakeHeadH
  cmp #$02
  bcc wrapTop
  lda snakeHeadL
  ora #$1f
  sta snakeHeadL
  rts
wrapTop:
  lda #$05
  sta snakeHeadH
  lda snakeHeadL
  ora #$1f
  sta snakeHeadL
  rts

clearScreen:
  lda #0
  ldx #0
clrLoop:
  sta $0200,x
  sta $0300,x
  sta $0400,x
  sta $0500,x
  inx
  bne clrLoop
  rts

drawSnake:
  ldy #0
  lda #$FF
  
  ;draw head
  sta (snakeHeadL),y
  
  ;draw first body segment
  sta ($12),y
  
  ;draw second body segment
  sta ($14),y
  rts

delay:
  ldy #$20
delayloop:
  ldx #0
innerdelay:
  dex
  bne innerdelay
  dey
  bne delayloop
  rts


Video of moving with wasd

We now have a working snake smoothly moving aroudn the screen. First i introduced the initSnake which sets up the initial position and direction of our snake. The head position and two additional body segments are initialized here.

initSnake:
  lda #movingRight
  sta snakeDirection

  lda #$00
  sta snakeHeadL
  lda #$03
  sta snakeHeadH

  ; body segment positions (behind head initially)
  lda #$1F
  sta $12       ; segment 1 low
  lda #$02
  sta $13       ; segment 1 high

  lda #$1E
  sta $14       ; segment 2 low
  lda #$02
  sta $15       ; segment 2 high
  rts

The core logic of our game runs continously in mainLoop, ensuring constant updates and responsiveness. Each iteration of the loop processors user input (readKeys), updates the snake's position (updateSnake), clears the screen (clearScreen), redraws the snake (drawSnake), and introduces a visual delay.

mainLoop:
  jsr readKeys
  jsr updateSnake
  jsr clearScreen
  jsr drawSnake
  jsr delay
  jmp mainLoop

The readKeys connects with WASD keys to find direction and includes checks to prevent isntant reversal of the snake's direction, which we mentioned previously that it should be prohibited.

readKeys:
  lda sysLastKey
  cmp #ASCII_w
  beq upKey
  cmp #ASCII_d
  beq rightKey
  cmp #ASCII_s
  beq downKey
  cmp #ASCII_a
  beq leftKey
  rts

upKey:
  lda #movingDown
  bit snakeDirection
  bne illegalMove
  lda #movingUp
  sta snakeDirection
  rts

rightKey:
  lda #movingLeft
  bit snakeDirection
  bne illegalMove
  lda #movingRight
  sta snakeDirection
  rts

downKey:
  lda #movingUp
  bit snakeDirection
  bne illegalMove
  lda #movingDown
  sta snakeDirection
  rts

leftKey:
  lda #movingRight
  bit snakeDirection
  bne illegalMove
  lda #movingLeft
  sta snakeDirection
  rts

illegalMove:
  rts


In updateSnake each body segment's position is shifted forward, effectively following the head. Then the head is moved according to the current direction. Also made it reappear from opposite side of screen when it goes over the screen.

updateSnake:
; shift body positions first (segments follow head)
  lda $14
  sta $12
  lda $15
  sta $13

  lda snakeHeadL
  sta $14
  lda snakeHeadH
  sta $15

; then update head based on direction
  lda snakeDirection
  lsr
  bcs up
  lsr
  bcs right
  lsr
  bcs down
  lsr
  bcs left
  rts

And clearScreen resets all pixels to back ($00), ensuring only the current snake position is shown clearly:

clearScreen:
  lda #0
  ldx #0
clrLoop:
  sta $0200,x
  sta $0300,x
  sta $0400,x
  sta $0500,x
  inx
  bne clrLoop
  rts


Next we can implement apple and disappearing apple when snake hits them!

; === Definitions ===
define snakeHeadL     $10 ; head low byte
define snakeHeadH     $11 ; head high byte
define snakeBodyStart $12 ; body segments
define snakeDirection $02

define appleL         $20 ; apple low byte
define appleH         $21 ; apple high byte

define movingUp       1
define movingRight    2
define movingDown     4
define movingLeft     8

define ASCII_w        $77
define ASCII_a        $61
define ASCII_s        $73
define ASCII_d        $64

define sysLastKey     $ff
define sysRandom      $fe ; emulator random byte
define SCREEN         $0200

  jsr initSnake
  jsr spawnApple     ; NEW: initial apple spawn

mainLoop:
  jsr readKeys
  jsr updateSnake
  jsr checkApple     ; NEW: check collision with apple
  jsr clearScreen
  jsr drawApple      ; NEW: draw apple
  jsr drawSnake
  jsr delay
  jmp mainLoop

initSnake:
  lda #movingRight
  sta snakeDirection

  lda #$00
  sta snakeHeadL
  lda #$03
  sta snakeHeadH

  ; snake body (2 segments)
  lda #$1F
  sta $12
  lda #$02
  sta $13

  lda #$1E
  sta $14
  lda #$02
  sta $15
  rts

; === Spawn Apple at random ===
spawnApple:
  lda sysRandom
  and #$1F
  sta appleL

  lda sysRandom
  and #$03
  clc
  adc #$02
  sta appleH
  rts

; === Check collision snake-apple ===
checkApple:
  lda snakeHeadL
  cmp appleL
  bne noApple
  lda snakeHeadH
  cmp appleH
  bne noApple

  jsr spawnApple  ; respawn apple if eaten

noApple:
  rts

readKeys:
  lda sysLastKey
  cmp #ASCII_w
  beq upKey
  cmp #ASCII_d
  beq rightKey
  cmp #ASCII_s
  beq downKey
  cmp #ASCII_a
  beq leftKey
  rts

upKey:
  lda #movingDown
  bit snakeDirection
  bne illegalMove
  lda #movingUp
  sta snakeDirection
  rts

rightKey:
  lda #movingLeft
  bit snakeDirection
  bne illegalMove
  lda #movingRight
  sta snakeDirection
  rts

downKey:
  lda #movingUp
  bit snakeDirection
  bne illegalMove
  lda #movingDown
  sta snakeDirection
  rts

leftKey:
  lda #movingRight
  bit snakeDirection
  bne illegalMove
  lda #movingLeft
  sta snakeDirection
  rts

illegalMove:
  rts

updateSnake:
; shift body positions
  lda $14
  sta $12
  lda $15
  sta $13
  lda snakeHeadL
  sta $14
  lda snakeHeadH
  sta $15

; move head
  lda snakeDirection
  lsr
  bcs up
  lsr
  bcs right
  lsr
  bcs down
  lsr
  bcs left
  rts

up:
  lda snakeHeadL
  sec
  sbc #$20
  sta snakeHeadL
  bcc upwrap
  rts
upwrap:
  dec snakeHeadH
  lda snakeHeadH
  cmp #$02
  bcc setBottom
  rts
setBottom:
  lda #$05
  sta snakeHeadH
  rts

right:
  inc snakeHeadL
  lda snakeHeadL
  and #$1f
  beq wrapRight
  rts
wrapRight:
  sec
  lda snakeHeadL
  sbc #$20
  sta snakeHeadL
  inc snakeHeadH
  lda snakeHeadH
  cmp #$06
  bne noWrapRight
  lda #$02
  sta snakeHeadH
noWrapRight:
  rts

down:
  lda snakeHeadL
  clc
  adc #$20
  sta snakeHeadL
  bcs downwrap
  rts
downwrap:
  inc snakeHeadH
  lda snakeHeadH
  cmp #$06
  bne noWrapDown
  lda #$02
  sta snakeHeadH
noWrapDown:
  rts

left:
  dec snakeHeadL
  lda snakeHeadL
  and #$1f
  cmp #$1f
  beq leftwrap
  rts
leftwrap:
  dec snakeHeadH
  lda snakeHeadH
  cmp #$02
  bcc wrapTop
  lda snakeHeadL
  ora #$1f
  sta snakeHeadL
  rts
wrapTop:
  lda #$05
  sta snakeHeadH
  lda snakeHeadL
  ora #$1f
  sta snakeHeadL
  rts

clearScreen:
  lda #0
  ldx #0
clrLoop:
  sta $0200,x
  sta $0300,x
  sta $0400,x
  sta $0500,x
  inx
  bne clrLoop
  rts

; ===draw apple ===
drawApple:
  lda #$AA ; Apple color (distinct from snake)
  ldy #0
  sta (appleL),y
  rts

drawSnake:
  lda #$FF ; Snake color
  ldy #0
  sta (snakeHeadL),y
  sta ($12),y
  sta ($14),y
  rts

delay:
  ldy #$20
delayloop:
  ldx #0
innerdelay:
  dex
  bne innerdelay
  dey
  bne delayloop
  rts

We have now brought another part to our game here - apples! So for ths i started wth making spawnApple subroutine, which randomly positions apple on the screen each time the game begins and whenever snake hits them.

; === Spawn Apple at random ===
spawnApple:
  lda sysRandom
  and #$1F
  sta appleL

  lda sysRandom
  and #$03
  clc
  adc #$02
  sta appleH
  rts

in here sysRandom generates a random position within screen bounds, ensuring the apple appears unpredictable each time.



Next the drawApple subroutine visually represents the apple using a distinct color($AA)

; ===draw apple ===
drawApple:
  lda #$AA ; Apple color (distinct from snake)
  ldy #0
  sta (appleL),y
  rts


And now we have checkApple subroutine, which compares the apple's position with the snake head's current position and if they are matching then the apple has been eaten by snake. Then apple immediately respawns at a new random positon

; === Check collision snake-apple ===
checkApple:
  lda snakeHeadL
  cmp appleL
  bne noApple
  lda snakeHeadH
  cmp appleH
  bne noApple

  jsr spawnApple  ; respawn apple if eaten

noApple:
  rts



Okay i think now we have some important parts in placed, now lets go ahead and do the "Snake length increase on apple eating"


define snakeHeadL     $10
define snakeHeadH     $11
define snakeLength    $12
define snakeDirection $13

define snakeBodyStart $30 ; Snake body starts here (many segments allowed)

define appleL         $80 ; Apple moved to safer location
define appleH         $81

define movingUp       1
define movingRight    2
define movingDown     4
define movingLeft     8

define ASCII_w        $77
define ASCII_a        $61
define ASCII_s        $73
define ASCII_d        $64

define sysLastKey     $ff
define sysRandom      $fe
define SCREEN         $0200

  jsr initSnake
  jsr spawnApple

mainLoop:
  jsr readKeys
  jsr updateSnake
  jsr checkApple
  jsr clearScreen
  jsr drawApple
  jsr drawSnake
  jsr delay
  jmp mainLoop

initSnake:
  lda #movingRight
  sta snakeDirection
  lda #3
  sta snakeLength

  lda #$00
  sta snakeHeadL
  lda #$03
  sta snakeHeadH

  ; initial snake body segments
  lda #$1F
  sta $30
  lda #$02
  sta $31

  lda #$1E
  sta $32
  lda #$02
  sta $33
  rts

spawnApple:
  lda sysRandom
  and #$1F
  sta appleL
  lda sysRandom
  and #$03
  clc
  adc #$02
  sta appleH
  rts

checkApple:
  lda snakeHeadL
  cmp appleL
  bne noApple
  lda snakeHeadH
  cmp appleH
  bne noApple

  ; Snake eats apple
  inc snakeLength    ; Increase snake length by 1
  jsr spawnApple     ; Respawn apple after eaten

noApple:
  rts

readKeys:
  lda sysLastKey
  cmp #ASCII_w
  beq upKey
  cmp #ASCII_d
  beq rightKey
  cmp #ASCII_s
  beq downKey
  cmp #ASCII_a
  beq leftKey
  rts

upKey:
  lda #movingDown
  bit snakeDirection
  bne illegalMove
  lda #movingUp
  sta snakeDirection
  rts

rightKey:
  lda #movingLeft
  bit snakeDirection
  bne illegalMove
  lda #movingRight
  sta snakeDirection
  rts

downKey:
  lda #movingUp
  bit snakeDirection
  bne illegalMove
  lda #movingDown
  sta snakeDirection
  rts

leftKey:
  lda #movingRight
  bit snakeDirection
  bne illegalMove
  lda #movingLeft
  sta snakeDirection
  rts

illegalMove:
  rts

updateSnake:
  ldx snakeLength
  dex
  txa
  asl
  tax

shiftLoop:
  cpx #2
  bcc shiftDone
  lda $2E,x    ; snakeHeadL ($10,$11) = body-2 = $2E,$2F
  sta $30,x
  lda $2F,x
  sta $31,x
  dex
  dex
  jmp shiftLoop

shiftDone:
  lda snakeHeadL
  sta $30
  lda snakeHeadH
  sta $31

  lda snakeDirection
  lsr
  bcs up
  lsr
  bcs right
  lsr
  bcs down
  lsr
  bcs left
  rts

up:
  lda snakeHeadL
  sec
  sbc #$20
  sta snakeHeadL
  bcc upwrap
  rts
upwrap:
  dec snakeHeadH
  lda snakeHeadH
  cmp #$02
  bcc setBottom
  rts
setBottom:
  lda #$05
  sta snakeHeadH
  rts

right:
  inc snakeHeadL
  lda snakeHeadL
  and #$1f
  beq wrapRight
  rts
wrapRight:
  sec
  lda snakeHeadL
  sbc #$20
  sta snakeHeadL
  inc snakeHeadH
  lda snakeHeadH
  cmp #$06
  bne noWrapRight
  lda #$02
  sta snakeHeadH
noWrapRight:
  rts

down:
  lda snakeHeadL
  clc
  adc #$20
  sta snakeHeadL
  bcs downwrap
  rts
downwrap:
  inc snakeHeadH
  lda snakeHeadH
  cmp #$06
  bne noWrapDown
  lda #$02
  sta snakeHeadH
noWrapDown:
  rts

left:
  dec snakeHeadL
  lda snakeHeadL
  and #$1f
  cmp #$1f
  beq leftwrap
  rts
leftwrap:
  dec snakeHeadH
  lda snakeHeadH
  cmp #$02
  bcc wrapTop
  lda snakeHeadL
  ora #$1f
  sta snakeHeadL
  rts
wrapTop:
  lda #$05
  sta snakeHeadH
  lda snakeHeadL
  ora #$1f
  sta snakeHeadL
  rts

clearScreen:
  lda #0
  ldx #0
clrLoop:
  sta $0200,x
  sta $0300,x
  sta $0400,x
  sta $0500,x
  inx
  bne clrLoop
  rts

drawApple:
  lda #$AA
  ldy #0
  sta (appleL),y
  rts

drawSnake:
  ldy #0
  lda #$FF
  sta (snakeHeadL),y ; head

  ldx #0
drawBodyLoop:
  lda $30,x
  sta $00
  lda $31,x
  sta $01
  lda #$FF
  sta ($00),y
  inx
  inx
  cpx snakeLength
  bcc drawBodyLoop
  rts

delay:
  ldy #$20
delayloop:
  ldx #0
innerdelay:
  dex
  bne innerdelay
  dey
  bne delayloop
  rts


In the here we implemented logic that allows our snake to detect and respond when it successfully eats an apple. Each frame, the snake's head position is compared with apple's position, and if horizontal or vertical positions match same then we say snake has eaten the apple. And then we increment the snake's length with inc snakeLength to make it grow one segment.

checkApple:
  lda snakeHeadL
  cmp appleL
  bne noApple
  lda snakeHeadH
  cmp appleH
  bne noApple

  ; Snake eats apple
  inc snakeLength    ; Increase snake length by 1
  jsr spawnApple     ; Respawn apple after eaten

noApple:
  rts



reference:

https://skilldrick.github.io/easy6502/

Monday, March 10, 2025

8th Posting: Project 1

For this project we are going to make custom GCC pass for our GCC compiler that we done in Lab 4. The requirements simply follows:

Create a pass for the current development version of the GCC compiler which:

  1. Iterates through the code being compiled;
  2. Prints the name of every function being compiled;
  3. Prints a count of the number of basic blocks in each function; and
  4. Prints a count of the number of gimple statements in each function.

Before we start anything lets go ahead and recap the file structures with ll command



So if we go back and see we have these build and test directory, as well as the source directory that we ran git clone. Lets get into the source directory and get into gcc folder
We see a huge directory with a lot of different files here!  we are now going to create a file called tree-sj-pass.cc and add our basic gcc pass code as below

#include "config.h"

#include "system.h"

#include "coretypes.h"

#include "backend.h"

#include "tree-pass.h"

#include "pass_manager.h"

#include "context.h"

#include "diagnostic-core.h"

#include "tree.h"

#include "tree-core.h"

#include "basic-block.h"

#include "gimple.h"

#include "gimple-iterator.h"


namespace {


// Define pass metadata

const pass_data sj_pass_data = {

    GIMPLE_PASS,          // Pass type

    "tree-sj-pass",   // Pass name

    OPTGROUP_NONE,        // No optimization group

    TV_TREE_OPS,          // Timevar

    0, 0, 0, 0           // Default settings

};


// Custom GIMPLE pass class

class sj_pass : public gimple_opt_pass {

public:

    // Constructor

    sj_pass(gcc::context *ctxt) : gimple_opt_pass(sj_pass_data, ctxt) {}


    // Gate function - always true

    bool gate(function *fun) override {

        return fun != nullptr;

    }


    // Main execution function

    unsigned int execute(function *fun) override {

        fprintf(stderr, "Processing function: %s\n", function_name(fun));


        int basic_block_count = 0, gimple_stmt_count = 0;


        // Iterate over basic blocks

        basic_block bb;

        FOR_EACH_BB_FN(bb, fun) {

            if (!bb) continue;  // Safety check

            basic_block_count++;


            // Iterate over GIMPLE statements

            for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {

                gimple_stmt_count++;

            }

}


// Print results

        fprintf(stderr, "Number of basic blocks: %d\nNumber of GIMPLE statements: %d\n",

                basic_block_count, gimple_stmt_count);


        return 0;

    }

};

}


// Factory function to create an instance of the pass

gimple_opt_pass *make_tree_sj_pass(gcc::context *ctxt) {

    return new sj_pass(ctxt);


}





Now we are modifying tree-pass.h file to register our newly made file tree-sj-pass.cc
(Looking back made some weird mistake here with typo with dashes..as well as context typo)

Then now we are modifying passes.def 

Then now we are adding tree-sj-pass.o to Makefile.in which is in the same directory to make sure that GCC includes my pass in build process.


Now since Makefile has been modified we are going to rebuild it.


;;; currently encountering linkage error with tree-sj-pass.o, will continue to attempt and update here.

--update, seems like it was relate to namespace error,  now i am running 
make clean in build directory
then build again with
time make -j$(nproc) |& tee make.log
And now we are encountering another error that is relate to configuring libgcc, currently on investigating and work in process..



RE-starting from scratch:
Currently recloning everything again to try from scratch.

Make install works successfully:


Now we are going back and adding a basic pass file again which is tree-sj.cc same as above code for basic pass but just a different names and conventions.

#include "config.h"


#include "system.h"

#include "coretypes.h"

#include "backend.h"

#include "tree-pass.h"

#include "pass_manager.h"

#include "context.h"

#include "diagnostic-core.h"

#include "tree.h"

#include "tree-core.h"

#include "basic-block.h"

#include "gimple.h"

#include "gimple-iterator.h"


namespace {


// Define pass metadata

const pass_data tree_sj_pass_data = {

    GIMPLE_PASS,         // Pass type

    "tree-sj",           // Pass name

    OPTGROUP_NONE, // No optimization group

    TV_TREE_OPS,         // Timevar

    0, 0, 0, 0           // Default settings

};


// Custom GIMPLE pass class

class tree_sj_pass : public gimple_opt_pass {

public:

    // Constructor

    tree_sj_pass(gcc::context *ctxt) : gimple_opt_pass(tree_sj_pass_data, ctxt) {}


    // Gate function - always true

    bool gate(function *fun) override {

        return fun != nullptr;

    }


    // Main execution function

    unsigned int execute(function *fun) override {

        fprintf(stderr, "[tree-sj] Processing function: %s\n", function_name(fun));


        int basic_block_count = 0;

        int gimple_stmt_count = 0;

        basic_block bb;

        // Iterate over basic blocks

        FOR_EACH_BB_FN(bb, fun) {

            if (!bb) continue;  // Safety check

            basic_block_count++;


            // Iterate over GIMPLE statements

            for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {

                gimple_stmt_count++;

            }

}


// Print results

        fprintf(stderr, "[tree-sj] Basic Blocks: %d | GIMPLE Statements: %d\n",

                basic_block_count, gimple_stmt_count);


        return 0;

    }

};


} // namespace

Save and exit, and edit tree-pass.h to add declaration for recognizing our function.

extern gimple_opt_pass *make_pass_harden_control_flow_redundancy (gcc::context

                                                                  *ctxt);

extern gimple_opt_pass *make_pass_sj(gcc::context *ctxt);



and edit passes.def to ensure pass is running during compilation
for adding NEXT_PASS(pass_sj)


and edit Makefile.in  to ensure gcc includes my above basic pass.

        tree-complex.o \

        tree-data-ref.o \

        tree-sj.o \

        tree-dfa.o \

        tree-diagnostic.o \

        tree-diagnostic-client-data-hooks.o \

        tree-dump.o \


and edit passes.def to ensure pass is running during compilation




then if you run the build command again you will see its getting built

few things to remember while debugging :
- naming convention syntaxes are of course important, double check, doublecheck
- which line you are putting all those edits are important as well

  NEXT_PASS (pass_asan_O0);

  NEXT_PASS (pass_tsan_O0);

  NEXT_PASS (pass_sanopt);

  NEXT_PASS (pass_cleanup_eh);

  NEXT_PASS (pass_musttail);

  NEXT_PASS (pass_lower_resx);

  NEXT_PASS (pass_sj);

  NEXT_PASS (pass_nrv);

  NEXT_PASS (pass_gimple_isel);

  NEXT_PASS (pass_harden_conditiona



and i run a testing file from gcc-test directory 

slee569@x86-001:~/gcc-test-001$ /home/slee569/gcc-build-001/gcc/xgcc -B/home/slee569/gcc-build-001/gcc/ test.c -o test_c.out

./test_c.out

[tree-sj] Processing function: main

[tree-sj] Basic Blocks: 2 | GIMPLE Statements: 5

Hello from GCC!

PASS running test file here! hows it going!



and got the expected result that is running with my customized GCC pass.







This project was really really time consuming if you start to mess up some little details like typos... dont be like me and make sure whatever you write is consistent and keep think about the connection between .def .h makefile and your basic gcc pass. Also again make sure to edit the files in right place, i tried a lot of times with wrong placement(out of scope, linkage issue, ggc not finding certain things that i implemented, sometimes even suspecting xgcc might be corrupted but it turned out that i was the one who made mistakes on editing files..) i think its all coming from what we edited so make sure its in right lines.


------------------------------------------------
Summary:

🔴 Configuration Issues: Cache and environment inconsistencies made it hard to get a clean build.
🔴 Pass Registration Errors: Undefined references and missing make_pass_sj() function led to failed builds.
🔴 GCC Compilation Complexity: Minor changes could break the build, requiring a lot of debugging.

Successful Build: Despite errors, we eventually got a working customized GCC!
Custom Pass Execution: tree-sj executed and provided basic block & GIMPLE statistics.
Improved Debugging Skills: Learned to analyze config.log, build.log, and compiler errors efficiently.

Final Takeaway:

This project was a hands-on journey into compiler design, teaching us how GCC compiles, optimizes, and executes code. We overcame tough debugging challenges and built a working custom pass, reinforcing our understanding of compiler internals and optimization techniques. 





10th Posting - Project: Stage 3

 Hello All! now we are on the final stage of the project which is project 3. If you remember correctly from my Stage 2 posting, i was able t...