Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Zwinkau
libfirm
Commits
65a67751
Commit
65a67751
authored
Sep 17, 2009
by
Matthias Braun
Browse files
experimental beginning of a binary emitter I had lying around here
[r26539]
parent
ba9c9184
Changes
2
Hide whitespace changes
Inline
Side-by-side
ir/be/ia32/ia32_emitter.c
View file @
65a67751
...
...
@@ -2223,6 +2223,530 @@ static const lc_opt_table_entry_t ia32_emitter_options[] = {
LC_OPT_LAST
};
/* ==== Experimental binary emitter ==== */
static
unsigned
char
reg_map
[
N_ia32_gp_REGS
];
static
void
build_reg_map
(
void
)
{
reg_map
[
REG_EAX
]
=
0x0
;
reg_map
[
REG_ECX
]
=
0x1
;
reg_map
[
REG_EDX
]
=
0x2
;
reg_map
[
REG_EBX
]
=
0x3
;
reg_map
[
REG_ESP
]
=
0x4
;
reg_map
[
REG_EBP
]
=
0x5
;
reg_map
[
REG_ESI
]
=
0x6
;
reg_map
[
REG_EDI
]
=
0x7
;
}
/* Node: The following routines are supposed to append bytes, words, dwords
to the output stream.
Currently the implementation is stupid in that it still creates output
for an "assembler" in the form of .byte, .long
We will change this when enough infrastructure is there to create complete
machine code in memory/object files */
static
void
bemit8
(
const
unsigned
char
byte
)
{
be_emit_irprintf
(
"
\t
.byte 0x%x
\n
"
,
byte
);
be_emit_write_line
();
}
static
void
bemit16
(
const
unsigned
u16
)
{
be_emit_irprintf
(
"
\t
.word 0x%x
\n
"
,
u16
);
be_emit_write_line
();
}
static
void
bemit32
(
const
unsigned
u32
)
{
be_emit_irprintf
(
"
\t
.long 0x%x
\n
"
,
u32
);
be_emit_write_line
();
}
static
void
bemit_entity
(
ir_entity
*
entity
,
bool
entity_sign
,
int
offset
,
bool
is_relative
)
{
if
(
entity
==
NULL
)
{
bemit32
(
offset
);
return
;
}
/* the final version should remember the position in the bytestream
and patch it with the correct address at linktime... */
be_emit_cstring
(
"
\t
.long "
);
if
(
entity_sign
)
be_emit_char
(
'-'
);
set_entity_backend_marked
(
entity
,
1
);
be_gas_emit_entity
(
entity
);
if
(
is_relative
)
{
be_emit_cstring
(
"-."
);
}
if
(
offset
!=
0
)
{
be_emit_irprintf
(
"%+d"
,
offset
);
}
be_emit_char
(
'\n'
);
be_emit_write_line
();
}
/* end emit routines, all emitters following here should only use the functions
above. */
static
void
bemit_modrr
(
const
arch_register_t
*
op1_dest
,
const
arch_register_t
*
op2
)
{
unsigned
char
modrm
=
0xC0
;
modrm
|=
reg_map
[
op1_dest
->
index
];
modrm
|=
reg_map
[
op2
->
index
]
<<
3
;
bemit8
(
modrm
);
}
static
void
bemit_modru
(
const
arch_register_t
*
dest
,
unsigned
val
)
{
assert
(
val
<=
7
);
unsigned
char
modrm
=
0xC0
;
modrm
|=
reg_map
[
dest
->
index
];
modrm
|=
val
<<
3
;
bemit8
(
modrm
);
}
static
unsigned
get_imm_size
(
ir_entity
*
entity
,
int
offset
)
{
if
(
entity
!=
NULL
)
return
32
;
if
(
offset
>=
-
127
&&
offset
<
128
)
{
return
8
;
}
else
if
(
offset
>=
-
32768
&&
offset
<
32767
)
{
return
16
;
}
else
{
return
32
;
}
}
static
void
bemit_binop_with_imm
(
const
ir_node
*
node
,
unsigned
opimm8
,
unsigned
opimm32
,
unsigned
ruval
)
{
const
arch_register_t
*
reg
=
get_out_reg
(
node
,
0
);
const
ir_node
*
op
=
get_irn_n
(
node
,
n_ia32_binary_right
);
const
ia32_immediate_attr_t
*
attr
=
get_ia32_immediate_attr_const
(
op
);
unsigned
size
=
get_imm_size
(
attr
->
symconst
,
attr
->
offset
);
switch
(
size
)
{
case
8
:
bemit8
(
opimm8
);
bemit_modru
(
reg
,
ruval
);
bemit8
(
attr
->
offset
);
return
;
case
16
:
case
32
:
bemit8
(
opimm32
);
bemit_modru
(
reg
,
ruval
);
bemit_entity
(
attr
->
symconst
,
attr
->
sc_sign
,
attr
->
offset
,
false
);
return
;
}
panic
(
"invalid imm size?!?"
);
}
static
void
bemit_modsourceam
(
unsigned
dest_reg
,
const
ir_node
*
node
)
{
ir_entity
*
ent
=
get_ia32_am_sc
(
node
);
int
offs
=
get_ia32_am_offs_int
(
node
);
ir_node
*
base
=
get_irn_n
(
node
,
n_ia32_base
);
int
has_base
=
!
is_ia32_NoReg_GP
(
base
);
ir_node
*
index
=
get_irn_n
(
node
,
n_ia32_index
);
int
has_index
=
!
is_ia32_NoReg_GP
(
index
);
unsigned
modrm
=
0
;
unsigned
sib
=
0
;
unsigned
emitoffs
=
0
;
bool
emitsib
=
false
;
/* set the mod part depending on displacement */
if
(
ent
!=
NULL
)
{
modrm
|=
0x80
;
emitoffs
=
32
;
}
else
if
(
offs
==
0
)
{
emitoffs
=
0
;
}
else
if
(
offs
>=
-
127
&&
offs
<=
128
)
{
modrm
|=
0x40
;
emitoffs
=
8
;
}
else
{
modrm
|=
0x80
;
emitoffs
=
32
;
}
/* determine if we need a SIB byte */
if
(
has_index
)
{
const
arch_register_t
*
reg_index
=
arch_get_irn_register
(
index
);
assert
(
reg_index
->
index
!=
REG_ESP
);
sib
|=
reg_map
[
reg_index
->
index
]
<<
3
;
if
(
has_base
)
{
const
arch_register_t
*
reg
=
arch_get_irn_register
(
base
);
sib
|=
reg_map
[
reg
->
index
];
}
else
{
sib
|=
0x05
;
}
int
scale
=
get_ia32_am_scale
(
node
);
assert
(
scale
<
4
);
sib
|=
scale
<<
6
;
emitsib
=
true
;
}
/* determine modrm byte */
if
(
emitsib
)
{
modrm
|=
0x04
;
}
else
if
(
has_base
)
{
const
arch_register_t
*
reg
=
arch_get_irn_register
(
base
);
/* we are forced to emit a sib when base is ESP */
if
(
reg
->
index
==
REG_ESP
)
{
sib
=
0x24
;
emitsib
=
true
;
/* we are forced to emit a 32bit offset as EBP base without
offset is a special case for displacement without base */
}
else
if
(
reg
->
index
==
REG_EBP
&&
emitoffs
==
0
)
{
assert
(
(
modrm
&
0xC0
)
==
0
);
emitoffs
=
8
;
modrm
|=
0x40
;
}
modrm
|=
reg_map
[
reg
->
index
];
}
else
{
modrm
=
0x05
;
emitoffs
=
32
;
}
modrm
|=
dest_reg
<<
3
;
bemit8
(
modrm
);
if
(
emitsib
)
bemit8
(
sib
);
/* emit displacement */
if
(
emitoffs
==
8
)
{
bemit8
((
unsigned
)
offs
);
}
else
if
(
emitoffs
==
32
)
{
bemit_entity
(
ent
,
is_ia32_am_sc_sign
(
node
),
offs
,
false
);
}
}
static
void
bemit_binop
(
const
ir_node
*
node
,
unsigned
modrr
,
unsigned
am
)
{
const
arch_register_t
*
out
=
get_in_reg
(
node
,
n_ia32_binary_left
);
if
(
get_ia32_op_type
(
node
)
==
ia32_AddrModeS
)
{
bemit8
(
am
);
bemit_modsourceam
(
reg_map
[
out
->
index
],
node
);
}
else
{
const
arch_register_t
*
op2
=
get_in_reg
(
node
,
n_ia32_binary_right
);
assert
(
get_ia32_op_type
(
node
)
==
ia32_Normal
);
bemit8
(
modrr
);
bemit_modrr
(
out
,
op2
);
}
}
static
void
bemit_immediate
(
const
ir_node
*
node
,
bool
relative
)
{
const
ia32_immediate_attr_t
*
attr
=
get_ia32_immediate_attr_const
(
node
);
bemit_entity
(
attr
->
symconst
,
attr
->
sc_sign
,
attr
->
offset
,
relative
);
}
static
void
bemit_copy
(
const
ir_node
*
copy
)
{
const
ir_node
*
op
=
be_get_Copy_op
(
copy
);
const
arch_register_t
*
in
=
arch_get_irn_register
(
op
);
const
arch_register_t
*
out
=
arch_get_irn_register
(
copy
);
if
(
in
==
out
||
is_unknown_reg
(
in
))
return
;
/* copies of vf nodes aren't real... */
if
(
arch_register_get_class
(
in
)
==
&
ia32_reg_classes
[
CLASS_ia32_vfp
])
return
;
if
(
get_irn_mode
(
copy
)
==
mode_E
)
{
panic
(
"NIY"
);
}
else
{
assert
(
arch_register_get_class
(
in
)
==
&
ia32_reg_classes
[
CLASS_ia32_gp
]);
bemit8
(
0x89
);
bemit_modrr
(
out
,
in
);
}
}
static
void
bemit_xor0
(
const
ir_node
*
node
)
{
const
arch_register_t
*
out
=
get_out_reg
(
node
,
0
);
bemit8
(
0x31
);
bemit_modrr
(
out
,
out
);
}
static
void
bemit_const
(
const
ir_node
*
node
)
{
const
arch_register_t
*
out
=
get_out_reg
(
node
,
0
);
bemit8
(
0xB8
+
reg_map
[
out
->
index
]);
bemit_immediate
(
node
,
false
);
}
static
void
bemit_add
(
const
ir_node
*
node
)
{
ir_node
*
right
=
get_irn_n
(
node
,
n_ia32_binary_right
);
if
(
is_ia32_Immediate
(
right
))
{
/* TODO: there's a shorter variant with DEST=EAX */
bemit_binop_with_imm
(
node
,
0x83
,
0x81
,
0
);
}
else
{
bemit_binop
(
node
,
0x01
,
0x03
);
}
}
static
void
bemit_sub
(
const
ir_node
*
node
)
{
ir_node
*
right
=
get_irn_n
(
node
,
n_ia32_binary_right
);
if
(
is_ia32_Immediate
(
right
))
{
/* TODO: there's a shorter variant with DEST=EAX */
bemit_binop_with_imm
(
node
,
0x83
,
0x81
,
5
);
}
else
{
bemit_binop
(
node
,
0x29
,
0x2B
);
}
}
static
void
bemit_xor
(
const
ir_node
*
node
)
{
ir_node
*
right
=
get_irn_n
(
node
,
n_ia32_binary_right
);
if
(
is_ia32_Immediate
(
right
))
{
/* TODO: there's a shorter variant with DEST=EAX */
bemit_binop_with_imm
(
node
,
0x83
,
0x81
,
6
);
}
else
{
bemit_binop
(
node
,
0x31
,
0x33
);
}
}
static
void
bemit_not
(
const
ir_node
*
node
)
{
const
arch_register_t
*
reg
=
get_out_reg
(
node
,
0
);
bemit8
(
0xF7
);
bemit_modru
(
reg
,
2
);
}
static
void
bemit_lea
(
const
ir_node
*
node
)
{
const
arch_register_t
*
out
=
get_out_reg
(
node
,
0
);
bemit8
(
0x8D
);
bemit_modsourceam
(
reg_map
[
out
->
index
],
node
);
}
static
void
bemit_cltd
(
const
ir_node
*
node
)
{
(
void
)
node
;
bemit8
(
0x99
);
}
static
void
bemit_load
(
const
ir_node
*
node
)
{
const
arch_register_t
*
out
=
get_out_reg
(
node
,
0
);
/* TODO: load from constant address to EAX can be encoded
as 0xA1 [offset] */
bemit8
(
0x8B
);
bemit_modsourceam
(
reg_map
[
out
->
index
],
node
);
}
static
void
bemit_store
(
const
ir_node
*
node
)
{
const
ir_node
*
value
=
get_irn_n
(
node
,
n_ia32_Store_val
);
if
(
is_ia32_Immediate
(
value
))
{
bemit8
(
0xC7
);
bemit_modsourceam
(
0
,
node
);
bemit_immediate
(
value
,
false
);
}
else
{
/* TODO: store to constant address from EAX can be encoded as
0xA3 [offset]*/
const
arch_register_t
*
in
=
get_in_reg
(
node
,
n_ia32_Store_val
);
bemit8
(
0x89
);
bemit_modsourceam
(
reg_map
[
in
->
index
],
node
);
}
}
static
void
bemit_push
(
const
ir_node
*
node
)
{
const
ir_node
*
value
=
get_irn_n
(
node
,
n_ia32_Push_val
);
if
(
is_ia32_Immediate
(
value
))
{
const
ia32_immediate_attr_t
*
attr
=
get_ia32_immediate_attr_const
(
value
);
unsigned
size
=
get_imm_size
(
attr
->
symconst
,
attr
->
offset
);
/* TODO: check for bitsizes different from 32... */
switch
(
size
)
{
case
8
:
bemit8
(
0x6A
);
bemit8
(
attr
->
offset
);
break
;
case
16
:
case
32
:
bemit8
(
0x68
);
bemit_immediate
(
value
,
false
);
break
;
}
}
else
{
bemit8
(
0xFF
);
bemit_modsourceam
(
6
,
node
);
}
}
static
void
bemit_pop
(
const
ir_node
*
node
)
{
const
arch_register_t
*
reg
=
get_out_reg
(
node
,
pn_ia32_Pop_res
);
/* TODO: check for AM pop */
bemit8
(
0x58
+
reg_map
[
reg
->
index
]);
}
static
void
bemit_call
(
const
ir_node
*
node
)
{
ir_node
*
proc
=
get_irn_n
(
node
,
n_ia32_Call_addr
);
if
(
is_ia32_Immediate
(
proc
))
{
bemit8
(
0xE8
);
bemit_immediate
(
proc
,
true
);
}
else
{
panic
(
"indirect call NIY"
);
}
}
static
void
bemit_return
(
const
ir_node
*
node
)
{
unsigned
pop
=
be_Return_get_pop
(
node
);
if
(
pop
>
0
||
be_Return_get_emit_pop
(
node
))
{
bemit8
(
0xC2
);
assert
(
pop
<=
0xffff
);
bemit16
(
pop
);
}
else
{
bemit8
(
0xC3
);
}
}
static
void
bemit_incsp
(
const
ir_node
*
node
)
{
const
arch_register_t
*
reg
=
get_out_reg
(
node
,
0
);
int
offs
=
be_get_IncSP_offset
(
node
);
unsigned
size
=
get_imm_size
(
NULL
,
offs
);
if
(
offs
>
0
)
{
bemit8
(
size
==
8
?
0x83
:
0x81
);
bemit_modru
(
reg
,
5
);
/* sub */
if
(
size
==
8
)
{
bemit8
(
offs
);
}
else
{
bemit32
(
offs
);
}
}
else
if
(
offs
<
0
)
{
bemit8
(
size
==
8
?
0x83
:
0x81
);
bemit_modru
(
reg
,
0
);
/* add */
if
(
size
==
8
)
{
bemit8
(
-
offs
);
}
else
{
bemit32
(
-
offs
);
}
}
}
/**
* The type of a emitter function.
*/
typedef
void
(
*
emit_func
)
(
const
ir_node
*
);
/**
* Set a node emitter. Make it a bit more type safe.
*/
static
void
register_emitter
(
ir_op
*
op
,
emit_func
func
)
{
op
->
ops
.
generic
=
(
op_func
)
func
;
}
static
void
ia32_register_binary_emitters
(
void
)
{
/* first clear the generic function pointer for all ops */
clear_irp_opcodes_generic_func
();
/* benode emitter */
register_emitter
(
op_be_Copy
,
bemit_copy
);
register_emitter
(
op_be_Return
,
bemit_return
);
register_emitter
(
op_be_IncSP
,
bemit_incsp
);
register_emitter
(
op_ia32_Add
,
bemit_add
);
register_emitter
(
op_ia32_Call
,
bemit_call
);
register_emitter
(
op_ia32_Cltd
,
bemit_cltd
);
register_emitter
(
op_ia32_Sub
,
bemit_sub
);
register_emitter
(
op_ia32_Xor0
,
bemit_xor0
);
register_emitter
(
op_ia32_Xor
,
bemit_xor
);
register_emitter
(
op_ia32_Const
,
bemit_const
);
register_emitter
(
op_ia32_Lea
,
bemit_lea
);
register_emitter
(
op_ia32_Load
,
bemit_load
);
register_emitter
(
op_ia32_Not
,
bemit_not
);
register_emitter
(
op_ia32_Push
,
bemit_push
);
register_emitter
(
op_ia32_Pop
,
bemit_pop
);
register_emitter
(
op_ia32_Store
,
bemit_store
);
/* ignore the following nodes */
register_emitter
(
op_ia32_ProduceVal
,
emit_Nothing
);
register_emitter
(
op_be_Barrier
,
emit_Nothing
);
register_emitter
(
op_be_Keep
,
emit_Nothing
);
register_emitter
(
op_be_RegParams
,
emit_Nothing
);
register_emitter
(
op_Phi
,
emit_Nothing
);
register_emitter
(
op_Start
,
emit_Nothing
);
}
static
void
gen_binary_block
(
ir_node
*
block
)
{
ir_node
*
node
;
ia32_emit_block_header
(
block
);
/* emit the contents of the block */
sched_foreach
(
block
,
node
)
{
ia32_emit_node
(
node
);
}
}
void
ia32_gen_binary_routine
(
ia32_code_gen_t
*
ia32_cg
,
ir_graph
*
irg
)
{
ir_entity
*
entity
=
get_irg_entity
(
irg
);
int
i
,
n
;
cg
=
ia32_cg
;
isa
=
cg
->
isa
;
ia32_register_binary_emitters
();
be_gas_emit_function_prolog
(
entity
,
ia32_cg_config
.
function_alignment
);
/* we use links to point to target blocks */
ir_reserve_resources
(
irg
,
IR_RESOURCE_IRN_LINK
);
irg_block_walk_graph
(
irg
,
ia32_gen_labels
,
NULL
,
NULL
);
/* initialize next block links */
n
=
ARR_LEN
(
cg
->
blk_sched
);
for
(
i
=
0
;
i
<
n
;
++
i
)
{
ir_node
*
block
=
cg
->
blk_sched
[
i
];
ir_node
*
prev
=
i
>
0
?
cg
->
blk_sched
[
i
-
1
]
:
NULL
;
set_irn_link
(
block
,
prev
);
}
for
(
i
=
0
;
i
<
n
;
++
i
)
{
ir_node
*
block
=
cg
->
blk_sched
[
i
];
gen_binary_block
(
block
);
}
be_gas_emit_function_epilog
(
entity
);
be_dbg_method_end
();
be_emit_char
(
'\n'
);
be_emit_write_line
();
ir_free_resources
(
irg
,
IR_RESOURCE_IRN_LINK
);
}
void
ia32_init_emitter
(
void
)
{
lc_opt_entry_t
*
be_grp
;
...
...
@@ -2233,5 +2757,7 @@ void ia32_init_emitter(void)
lc_opt_add_table
(
ia32_grp
,
ia32_emitter_options
);
build_reg_map
();
FIRM_DBG_REGISTER
(
dbg
,
"firm.be.ia32.emitter"
);
}
ir/be/ia32/ia32_emitter.h
View file @
65a67751
...
...
@@ -53,6 +53,7 @@ void ia32_emit_am(const ir_node *node);
void
ia32_emit_x87_binop
(
const
ir_node
*
node
);
void
ia32_gen_routine
(
ia32_code_gen_t
*
cg
,
ir_graph
*
irg
);
void
ia32_gen_binary_routine
(
ia32_code_gen_t
*
ia32_cg
,
ir_graph
*
irg
);
/** Initializes the Emitter. */
void
ia32_init_emitter
(
void
);
...
...
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