Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Alexander Hirsch
703602-Compiler-Construction
Commits
e5bfabc3
Commit
e5bfabc3
authored
May 14, 2021
by
Alexander Hirsch
Browse files
Lab: Add CFG example
parent
7be66813
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
335 additions
and
0 deletions
+335
-0
lab/cfg/.gitignore
lab/cfg/.gitignore
+1
-0
lab/cfg/Makefile
lab/cfg/Makefile
+8
-0
lab/cfg/cfg.c
lab/cfg/cfg.c
+326
-0
No files found.
lab/cfg/.gitignore
0 → 100644
View file @
e5bfabc3
cfg
lab/cfg/Makefile
0 → 100644
View file @
e5bfabc3
CFLAGS
=
-std
=
c17
-Wall
-Wextra
-g3
all
:
cfg
clean
:
$(RM)
cfg
.PHONY
:
all clean
lab/cfg/cfg.c
0 → 100644
View file @
e5bfabc3
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
// -------------------------------------------------------------------- TAC Definition
enum
tac_instruction_op
{
TAC_INSTRUCTION_OP_CONST
,
TAC_INSTRUCTION_OP_ASSIGN
,
// Arithmetic operations
TAC_INSTRUCTION_OP_ADD
,
// ...
// Control flow
TAC_INSTRUCTION_OP_LABEL
,
TAC_INSTRUCTION_OP_JUMP
,
TAC_INSTRUCTION_OP_JUMP_IF
,
// Function calls
TAC_INSTRUCTION_OP_CALL
,
TAC_INSTRUCTION_OP_RETURN
,
TAC_INSTRUCTION_OP_PUSH
,
TAC_INSTRUCTION_OP_POP
,
};
const
char
*
tac_instruction_op_to_string
(
enum
tac_instruction_op
op
)
{
switch
(
op
)
{
case
TAC_INSTRUCTION_OP_CONST
:
return
"CONST"
;
case
TAC_INSTRUCTION_OP_ASSIGN
:
return
"ASSIGN"
;
case
TAC_INSTRUCTION_OP_ADD
:
return
"ADD"
;
case
TAC_INSTRUCTION_OP_LABEL
:
return
"LABEL"
;
case
TAC_INSTRUCTION_OP_JUMP
:
return
"JUMP"
;
case
TAC_INSTRUCTION_OP_JUMP_IF
:
return
"JUMP_IF"
;
case
TAC_INSTRUCTION_OP_CALL
:
return
"CALL"
;
case
TAC_INSTRUCTION_OP_RETURN
:
return
"RETURN"
;
case
TAC_INSTRUCTION_OP_PUSH
:
return
"PUSH"
;
case
TAC_INSTRUCTION_OP_POP
:
return
"POP"
;
}
assert
(
false
);
return
"INVALID"
;
}
bool
tac_is_jump
(
enum
tac_instruction_op
op
)
{
return
op
==
TAC_INSTRUCTION_OP_JUMP
||
op
==
TAC_INSTRUCTION_OP_JUMP_IF
;
}
struct
tac_function
{
char
name
[
256
];
struct
tac_instruction
*
start
;
};
struct
tac_instruction
{
enum
tac_instruction_op
op
;
uint64_t
label
;
const
char
*
function
;
struct
tac_instruction
*
next
;
};
void
append_instruction
(
struct
tac_function
*
function
,
struct
tac_instruction
instruction
)
{
assert
(
function
);
struct
tac_instruction
**
end
=
&
function
->
start
;
while
(
*
end
)
{
end
=
&
(
*
end
)
->
next
;
}
*
end
=
malloc
(
sizeof
(
**
end
));
assert
(
*
end
);
**
end
=
instruction
;
}
void
clear_instructions
(
struct
tac_function
*
function
)
{
assert
(
function
);
struct
tac_instruction
*
current
=
function
->
start
;
while
(
current
)
{
struct
tac_instruction
*
to_free
=
current
;
current
=
current
->
next
;
free
(
to_free
);
}
}
struct
tac_function
example_function
()
{
struct
tac_function
function
=
{
.
name
=
"example"
,
};
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_POP
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_CONST
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_CONST
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_ADD
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_ADD
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_JUMP_IF
,
.
label
=
1
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_ADD
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_ASSIGN
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_JUMP
,
.
label
=
2
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_LABEL
,
.
label
=
1
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_ADD
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_ASSIGN
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_LABEL
,
.
label
=
2
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_PUSH
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_PUSH
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_PUSH
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_CALL
,
.
function
=
"fun"
});
append_instruction
(
&
function
,
(
struct
tac_instruction
){.
op
=
TAC_INSTRUCTION_OP_RETURN
});
return
function
;
}
// -------------------------------------------------------------------- CFG Definition
struct
cfg_basic_block_instruction
{
struct
tac_instruction
*
instruction
;
struct
cfg_basic_block_instruction
*
next
;
};
struct
cfg_basic_block
{
struct
cfg_basic_block_instruction
*
instructions
;
struct
cfg_basic_block
*
next
;
};
struct
cfg_edge
{
struct
cfg_basic_block
*
from
,
*
to
;
struct
cfg_edge
*
next
;
};
struct
cfg_graph
{
struct
cfg_basic_block
*
first_basic_block
;
struct
cfg_edge
*
first_edge
;
};
void
add_instruction
(
struct
cfg_basic_block
*
block
,
struct
tac_instruction
*
instruction
)
{
assert
(
block
);
assert
(
instruction
);
struct
cfg_basic_block_instruction
**
end
=
&
block
->
instructions
;
while
(
*
end
)
{
end
=
&
(
*
end
)
->
next
;
}
*
end
=
malloc
(
sizeof
(
**
end
));
assert
(
*
end
);
**
end
=
(
struct
cfg_basic_block_instruction
){.
instruction
=
instruction
};
}
void
clear_instructions_from_basic_block
(
struct
cfg_basic_block
*
block
)
{
assert
(
block
);
struct
cfg_basic_block_instruction
*
current
=
block
->
instructions
;
while
(
current
)
{
struct
cfg_basic_block_instruction
*
to_free
=
current
;
current
=
current
->
next
;
free
(
to_free
);
}
}
struct
cfg_basic_block
*
add_basic_block
(
struct
cfg_graph
*
graph
)
{
assert
(
graph
);
struct
cfg_basic_block
**
end
=
&
graph
->
first_basic_block
;
while
(
*
end
)
{
end
=
&
(
*
end
)
->
next
;
}
*
end
=
malloc
(
sizeof
(
**
end
));
**
end
=
(
struct
cfg_basic_block
){};
return
*
end
;
}
void
add_edge
(
struct
cfg_graph
*
graph
,
struct
cfg_basic_block
*
from
,
struct
cfg_basic_block
*
to
)
{
assert
(
graph
);
assert
(
from
);
assert
(
to
);
struct
cfg_edge
**
end
=
&
graph
->
first_edge
;
while
(
*
end
)
{
end
=
&
(
*
end
)
->
next
;
}
*
end
=
malloc
(
sizeof
(
**
end
));
assert
(
*
end
);
**
end
=
(
struct
cfg_edge
){.
from
=
from
,
.
to
=
to
};
}
void
clear_graph
(
struct
cfg_graph
*
graph
)
{
assert
(
graph
);
{
struct
cfg_basic_block
*
current
=
graph
->
first_basic_block
;
while
(
current
)
{
struct
cfg_basic_block
*
to_free
=
current
;
current
=
current
->
next
;
clear_instructions_from_basic_block
(
to_free
);
free
(
to_free
);
}
}
{
struct
cfg_edge
*
current
=
graph
->
first_edge
;
while
(
current
)
{
struct
cfg_edge
*
to_free
=
current
;
current
=
current
->
next
;
free
(
to_free
);
}
}
}
// -------------------------------------------------------------------- CFG Generation
struct
cfg_graph
gen_graph
(
struct
tac_function
*
function
)
{
assert
(
function
);
struct
cfg_graph
graph
=
{};
struct
cfg_basic_block
*
block
=
add_basic_block
(
&
graph
);
struct
cfg_basic_block
*
jump_targets
[
256
]
=
{};
for
(
struct
tac_instruction
*
instruction
=
function
->
start
;
instruction
;
instruction
=
instruction
->
next
)
{
if
(
instruction
->
op
==
TAC_INSTRUCTION_OP_LABEL
)
{
// only split block if empty
if
(
block
->
instructions
)
{
struct
cfg_basic_block
*
next_block
=
add_basic_block
(
&
graph
);
add_edge
(
&
graph
,
block
,
next_block
);
block
=
next_block
;
}
// register as jump target
jump_targets
[
instruction
->
label
]
=
block
;
}
add_instruction
(
block
,
instruction
);
if
(
instruction
->
op
==
TAC_INSTRUCTION_OP_JUMP_IF
)
{
struct
cfg_basic_block
*
next_block
=
add_basic_block
(
&
graph
);
add_edge
(
&
graph
,
block
,
next_block
);
block
=
next_block
;
}
else
if
(
instruction
->
op
==
TAC_INSTRUCTION_OP_JUMP
)
{
block
=
add_basic_block
(
&
graph
);
}
}
// wire up jumps and labels
for
(
struct
cfg_basic_block
*
block
=
graph
.
first_basic_block
;
block
;
block
=
block
->
next
)
{
for
(
struct
cfg_basic_block_instruction
*
inst
=
block
->
instructions
;
inst
;
inst
=
inst
->
next
)
{
if
(
tac_is_jump
(
inst
->
instruction
->
op
))
{
add_edge
(
&
graph
,
block
,
jump_targets
[
inst
->
instruction
->
label
]);
}
}
}
return
graph
;
}
// -------------------------------------------------------------------- CFG Print
void
cfg_print
(
struct
cfg_graph
*
graph
)
{
assert
(
graph
);
puts
(
"digraph
\"
CFG
\"
{"
);
puts
(
"
\t
nodesep=0.6
\n
"
);
for
(
struct
cfg_basic_block
*
block
=
graph
->
first_basic_block
;
block
;
block
=
block
->
next
)
{
printf
(
"
\t\"
%p
\"
[shape=box, label=
\"
"
,
block
);
for
(
struct
cfg_basic_block_instruction
*
inst
=
block
->
instructions
;
inst
;
inst
=
inst
->
next
)
{
printf
(
"%s
\\
n"
,
tac_instruction_op_to_string
(
inst
->
instruction
->
op
));
}
puts
(
"
\"
];"
);
}
for
(
struct
cfg_edge
*
edge
=
graph
->
first_edge
;
edge
;
edge
=
edge
->
next
)
{
printf
(
"
\t\"
%p
\"
->
\"
%p
\"
;
\n
"
,
edge
->
from
,
edge
->
to
);
}
puts
(
"}"
);
}
// --------------------------------------------------------------------
int
main
(
void
)
{
struct
tac_function
example
=
example_function
();
struct
cfg_graph
graph
=
gen_graph
(
&
example
);
cfg_print
(
&
graph
);
clear_graph
(
&
graph
);
clear_instructions
(
&
example
);
return
EXIT_SUCCESS
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment