# attr_type => "ia32_imm_t",
#},
+Asm => {
+ mode => "mode_T",
+ arity => "variable",
+ out_arity => "variable",
+},
+
#-----------------------------------------------------------------#
# _ _ _ #
# (_) | | | | #
Add => {
irn_flags => "R",
- comment => "construct Add: Add(a, b) = Add(b, a) = a + b",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
ins => [ "base", "index", "left", "right", "mem" ],
emit => '. add%M %binop',
},
Adc => {
- comment => "construct Add with Carry: Adc(a, b) = Add(b, a) = a + b + carry",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. adc%M %binop',
units => [ "GP" ],
Add64Bit => {
irn_flags => "R",
- comment => "construct 64Bit Add: Add(a_l, a_h, b_l, b_h) = a_l + b_l; a_h + b_h + carry",
arity => 4,
reg_req => { in => [ "gp", "gp", "gp", "gp" ], out => [ "!in", "!in" ] },
emit => '
op_flags => "C",
irn_flags => "R",
cmp_attr => "return 1;",
- comment => "construct lowered Add: Add(a, b) = Add(b, a) = a + b",
arity => 2,
},
l_Adc => {
op_flags => "C",
cmp_attr => "return 1;",
- comment => "construct lowered Add with Carry: Adc(a, b) = Adc(b, a) = a + b + carry",
arity => 2,
},
Mul => {
# we should not rematrialize this node. It produces 2 results and has
# very strict constrains
- comment => "construct MulS: MulS(a, b) = MulS(b, a) = a * b",
reg_req => { in => [ "gp", "gp", "eax", "gp", "none" ], out => [ "eax", "edx", "none" ] },
emit => '. mul%M %unop',
outs => [ "EAX", "EDX", "M" ],
# very strict constrains
op_flags => "C",
cmp_attr => "return 1;",
- comment => "construct lowered MulS: Mul(a, b) = Mul(b, a) = a * b",
outs => [ "EAX", "EDX", "M" ],
arity => 2
},
IMul => {
irn_flags => "R",
- comment => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. imul%M %binop',
latency => 5,
IMul1OP => {
irn_flags => "R",
- comment => "construct Mul (1 operand format): Mul(a, b) = Mul(b, a) = a * b",
reg_req => { in => [ "gp", "gp", "eax", "gp", "none" ], out => [ "eax", "edx", "none" ] },
emit => '. imul%M %unop',
outs => [ "EAX", "EDX", "M" ],
l_IMul => {
op_flags => "C",
cmp_attr => "return 1;",
- comment => "construct lowered IMul: IMul(a, b) = IMul(b, a) = a * b",
arity => 2
},
And => {
irn_flags => "R",
- comment => "construct And: And(a, b) = And(b, a) = a AND b",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. and%M %binop',
units => [ "GP" ],
Or => {
irn_flags => "R",
- comment => "construct Or: Or(a, b) = Or(b, a) = a OR b",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. or%M %binop',
units => [ "GP" ],
Xor => {
irn_flags => "R",
- comment => "construct Xor: Xor(a, b) = Xor(b, a) = a EOR b",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. xor%M %binop',
units => [ "GP" ],
l_Xor => {
op_flags => "C",
cmp_attr => "return 1;",
- comment => "construct lowered Xor: Xor(a, b) = Xor(b, a) = a XOR b",
arity => 2,
modified_flags => $status_flags
},
Sub => {
irn_flags => "R",
- comment => "construct Sub: Sub(a, b) = a - b",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. sub%M %binop',
units => [ "GP" ],
},
Sbb => {
- comment => "construct Sub with Carry: SubC(a, b) = a - b - carry",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3 !in_r4" ] },
emit => '. sbb%M %binop',
units => [ "GP" ],
Sub64Bit => {
irn_flags => "R",
- comment => "construct 64Bit Sub: Sub(a_l, a_h, b_l, b_h) = a_l - b_l; a_h - b_h - borrow",
arity => 4,
reg_req => { in => [ "gp", "gp", "gp", "gp" ], out => [ "!in", "!in" ] },
emit => '
l_Sub => {
irn_flags => "R",
cmp_attr => "return 1;",
- comment => "construct lowered Sub: Sub(a, b) = a - b",
arity => 2,
},
l_Sbb => {
cmp_attr => "return 1;",
- comment => "construct lowered Sub with Carry: SubC(a, b) = a - b - carry",
arity => 2,
},
Shl => {
irn_flags => "R",
- comment => "construct Shl: Shl(a, b) = a << b",
reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
ins => [ "base", "index", "left", "right", "mem" ],
emit => '. shl%M %binop',
l_Shl => {
cmp_attr => "return 1;",
- comment => "construct lowered Shl: Shl(a, b) = a << b",
arity => 2
},
ShlD => {
irn_flags => "R",
- comment => "construct ShlD: ShlD(a, b, c) = a, b << count (shift left count bits from b into a)",
# Out requirements is: different from all in
# This is because, out must be different from LowPart and ShiftCount.
# We could say "!ecx !in_r4" but it can occur, that all values live through
l_ShlD => {
cmp_attr => "return 1;",
- comment => "construct lowered ShlD: ShlD(a, b, c) = a, b << count (shift left count bits from b into a)",
arity => 3,
},
Shr => {
irn_flags => "R",
- comment => "construct Shr: Shr(a, b) = a >> b",
reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
emit => '. shr%M %binop',
units => [ "GP" ],
l_Shr => {
cmp_attr => "return 1;",
- comment => "construct lowered Shr: Shr(a, b) = a << b",
arity => 2
},
ShrD => {
irn_flags => "R",
- comment => "construct ShrD: ShrD(a, b, c) = a, b >> count (shift rigth count bits from a into b)",
# Out requirements is: different from all in
# This is because, out must be different from LowPart and ShiftCount.
# We could say "!ecx !in_r4" but it can occur, that all values live through
l_ShrD => {
cmp_attr => "return 1;",
- comment => "construct lowered ShrD: ShrD(a, b, c) = a, b >> count (shift rigth count bits from a into b)",
arity => 3
},
Sar => {
irn_flags => "R",
- comment => "construct Shrs: Shrs(a, b) = a >> b",
reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
emit => '. sar%M %binop',
units => [ "GP" ],
l_Sar => {
cmp_attr => "return 1;",
- comment => "construct lowered Sar: Sar(a, b) = a << b",
arity => 2
},
Ror => {
irn_flags => "R",
- comment => "construct Ror: Ror(a, b) = a ROR b",
reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
emit => '. ror%M %binop',
units => [ "GP" ],
Rol => {
irn_flags => "R",
- comment => "construct Rol: Rol(a, b) = a ROL b",
reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] },
emit => '. rol%M %binop',
units => [ "GP" ],
Neg => {
irn_flags => "R",
- comment => "construct Minus: Minus(a) = -a",
reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. neg%M %unop',
units => [ "GP" ],
Minus64Bit => {
irn_flags => "R",
- comment => "construct 64Bit Minus: Minus(a_l, a_h, 0) = 0 - a_l; 0 - a_h - borrow",
- arity => 4,
reg_req => { in => [ "gp", "gp", "gp" ], out => [ "!in", "!in" ] },
emit => '
. movl %S0, %D0
l_Neg => {
cmp_attr => "return 1;",
- comment => "construct lowered Minus: Minus(a) = -a",
arity => 1,
},
Inc => {
irn_flags => "R",
- comment => "construct Increment: Inc(a) = a++",
reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. inc%M %unop',
units => [ "GP" ],
Dec => {
irn_flags => "R",
- comment => "construct Decrement: Dec(a) = a--",
reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. dec%M %unop',
units => [ "GP" ],
Not => {
irn_flags => "R",
- comment => "construct Not: Not(a) = !a",
reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
emit => '. not%M %unop',
units => [ "GP" ],
CondJmp => {
state => "pinned",
op_flags => "L|X|Y",
- comment => "construct conditional jump: CMP A, B && JMPxx LABEL",
- reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ] },
+ reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "none", "none"] },
outs => [ "false", "true" ],
latency => 3,
units => [ "BRANCH" ],
TestJmp => {
state => "pinned",
op_flags => "L|X|Y",
- comment => "construct conditional jump: TEST A, B && JMPxx LABEL",
- reg_req => { in => [ "gp", "gp" ] },
+ reg_req => { in => [ "gp", "gp" ], out => [ "none", "none" ] },
outs => [ "false", "true" ],
latency => 3,
units => [ "BRANCH" ],
CJmpAM => {
state => "pinned",
op_flags => "L|X|Y",
- comment => "construct conditional jump without CMP (replaces CondJmp): JMPxx LABEL",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "none", "none" ] },
outs => [ "false", "true" ],
units => [ "BRANCH" ],
CJmp => {
state => "pinned",
op_flags => "L|X|Y",
- comment => "construct conditional jump without CMP (replaces TestJmp): JMPxx LABEL",
reg_req => { in => [ "gp", "gp" ] },
units => [ "BRANCH" ],
},
SwitchJmp => {
state => "pinned",
op_flags => "L|X|Y",
- comment => "construct switch",
reg_req => { in => [ "gp" ], out => [ "none" ] },
latency => 3,
units => [ "BRANCH" ],
Const => {
op_flags => "c",
irn_flags => "R",
- comment => "represents an integer constant",
reg_req => { out => [ "gp" ] },
units => [ "GP" ],
mode => $mode_gp,
state => "pinned",
op_flags => "c",
irn_flags => "I",
- comment => "unknown value",
reg_req => { out => [ "gp_UKNWN" ] },
units => [],
emit => "",
state => "pinned",
op_flags => "c",
irn_flags => "I",
- comment => "unknown value",
reg_req => { out => [ "vfp_UKNWN" ] },
units => [],
emit => "",
state => "pinned",
op_flags => "c",
irn_flags => "I",
- comment => "unknown value",
reg_req => { out => [ "xmm_UKNWN" ] },
units => [],
emit => "",
state => "pinned",
op_flags => "c",
irn_flags => "I",
- comment => "noreg GP value",
reg_req => { out => [ "gp_NOREG" ] },
units => [],
emit => "",
state => "pinned",
op_flags => "c",
irn_flags => "I",
- comment => "noreg VFP value",
reg_req => { out => [ "vfp_NOREG" ] },
units => [],
emit => "",
state => "pinned",
op_flags => "c",
irn_flags => "I",
- comment => "noreg XMM value",
reg_req => { out => [ "xmm_NOREG" ] },
units => [],
emit => "",
state => "pinned",
op_flags => "c",
irn_flags => "I",
- comment => "change floating point control word",
reg_req => { out => [ "fp_cw" ] },
mode => $mode_fpcw,
latency => 3,
FldCW => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "load floating point control word FldCW(ptr, mem) = LD ptr -> reg",
reg_req => { in => [ "gp", "gp", "none" ], out => [ "fp_cw" ] },
latency => 5,
emit => ". fldcw %AM",
FnstCW => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "store floating point control word: FstCW(ptr, mem) = ST ptr -> reg",
reg_req => { in => [ "gp", "gp", "fp_cw", "none" ], out => [ "none" ] },
latency => 5,
emit => ". fnstcw %AM",
Cltd => {
# we should not rematrialize this node. It produces 2 results and has
# very strict constrains
- comment => "construct CDQ: sign extend EAX -> EDX:EAX",
reg_req => { in => [ "gp" ], out => [ "eax in_r1", "edx" ] },
emit => '. cltd',
outs => [ "EAX", "EDX" ],
Load => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "construct Load: Load(ptr, mem) = LD ptr -> reg",
reg_req => { in => [ "gp", "gp", "none" ], out => [ "gp", "none" ] },
latency => 3,
emit => ". mov%SE%ME%.l %AM, %D0",
l_Load => {
op_flags => "L|F",
cmp_attr => "return 1;",
- comment => "construct lowered Load: Load(ptr, mem) = LD ptr -> reg",
outs => [ "res", "M" ],
arity => 2,
},
op_flags => "L|F",
cmp_attr => "return 1;",
state => "exc_pinned",
- comment => "construct lowered Store: Store(ptr, val, mem) = ST ptr,val",
arity => 3,
mode => "mode_M",
},
Store => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "construct Store: Store(ptr, val, mem) = ST ptr,val",
reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] },
emit => '. mov%M %binop',
latency => 3,
Store8Bit => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "construct 8Bit Store: Store(ptr, val, mem) = ST ptr,val",
reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "none" ], out => ["none" ] },
emit => '. mov%M %binop',
latency => 3,
Lea => {
irn_flags => "R",
- comment => "construct Lea: Lea(a,b) = lea [a+b*const+offs] | res = a + b * const + offs with const = 0,1,2,4,8",
reg_req => { in => [ "gp", "gp" ], out => [ "in_r1" ] },
emit => '. leal %AM, %D0',
latency => 2,
},
Push => {
- comment => "push on the stack",
reg_req => { in => [ "gp", "gp", "gp", "esp", "none" ], out => [ "esp", "none" ] },
emit => '. push%M %unop',
outs => [ "stack:I|S", "M" ],
},
Pop => {
- comment => "pop a gp register from the stack",
reg_req => { in => [ "gp", "gp", "esp", "none" ], out => [ "esp", "gp", "none" ] },
emit => '. pop%M %unop',
outs => [ "stack:I|S", "res", "M" ],
},
Enter => {
- comment => "create stack frame",
- reg_req => { in => [ "esp" ], out => [ "ebp", "esp" ] },
+ reg_req => { in => [ "esp" ], out => [ "ebp", "esp", "none" ] },
emit => '. enter',
outs => [ "frame:I", "stack:I|S", "M" ],
latency => 15,
},
Leave => {
- comment => "destroy stack frame",
reg_req => { in => [ "esp", "ebp" ], out => [ "ebp", "esp" ] },
emit => '. leave',
outs => [ "frame:I", "stack:I|S" ],
AddSP => {
irn_flags => "I",
- comment => "allocate space on stack",
reg_req => { in => [ "gp", "gp", "esp", "gp", "none" ], out => [ "in_r3", "none" ] },
emit => '. addl %binop',
outs => [ "stack:S", "M" ],
SubSP => {
irn_flags => "I",
- comment => "free space on stack",
reg_req => { in => [ "gp", "gp", "esp", "gp", "none" ], out => [ "in_r3", "none" ] },
emit => '. subl %binop',
outs => [ "stack:S", "M" ],
LdTls => {
irn_flags => "R",
- comment => "get the TLS base address",
reg_req => { out => [ "gp" ] },
units => [ "GP" ],
},
# the int instruction
int => {
reg_req => { in => [ "none" ], out => [ "none" ] },
- comment => "software interrupt",
mode => "mode_M",
attr => "tarval *tv",
init_attr => "\tset_ia32_Immop_tarval(res, tv);",
xAdd => {
irn_flags => "R",
- comment => "construct SSE Add: Add(a, b) = Add(b, a) = a + b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] },
emit => '. add%XXM %binop',
latency => 4,
xMul => {
irn_flags => "R",
- comment => "construct SSE Mul: Mul(a, b) = Mul(b, a) = a * b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] },
emit => '. mul%XXM %binop',
latency => 4,
xMax => {
irn_flags => "R",
- comment => "construct SSE Max: Max(a, b) = Max(b, a) = a > b ? a : b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] },
emit => '. max%XXM %binop',
latency => 2,
xMin => {
irn_flags => "R",
- comment => "construct SSE Min: Min(a, b) = Min(b, a) = a < b ? a : b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] },
emit => '. min%XXM %binop',
latency => 2,
xAnd => {
irn_flags => "R",
- comment => "construct SSE And: And(a, b) = a AND b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] },
emit => '. andp%XSD %binop',
latency => 3,
xOr => {
irn_flags => "R",
- comment => "construct SSE Or: Or(a, b) = a OR b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] },
emit => '. orp%XSD %binop',
units => [ "SSE" ],
xXor => {
irn_flags => "R",
- comment => "construct SSE Xor: Xor(a, b) = a XOR b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] },
emit => '. xorp%XSD %binop',
latency => 3,
xAndNot => {
irn_flags => "R",
- comment => "construct SSE AndNot: AndNot(a, b) = a AND NOT b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3 !in_r4" ] },
emit => '. andnp%XSD %binop',
latency => 3,
xSub => {
irn_flags => "R",
- comment => "construct SSE Sub: Sub(a, b) = a - b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3" ] },
emit => '. sub%XXM %binop',
latency => 4,
xDiv => {
irn_flags => "R",
- comment => "construct SSE Div: Div(a, b) = a / b",
- reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3 !in_r4" ] },
+ reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3 !in_r4", "none" ] },
outs => [ "res", "M" ],
emit => '. div%XXM %binop',
latency => 16,
xCmp => {
irn_flags => "R",
- comment => "construct SSE Compare: Cmp(a, b) == a = a cmp b",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "in_r3 !in_r4" ] },
latency => 3,
units => [ "SSE" ],
xCondJmp => {
state => "pinned",
op_flags => "L|X|Y",
- comment => "construct conditional jump: UCOMIS A, B && JMPxx LABEL",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "none", "none" ] },
outs => [ "false", "true" ],
latency => 5,
xConst => {
op_flags => "c",
irn_flags => "R",
- comment => "represents a SSE constant",
reg_req => { out => [ "xmm" ] },
emit => '. mov%XXM %C, %D0',
latency => 2,
xLoad => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "construct SSE Load: Load(ptr, mem) = LD ptr",
reg_req => { in => [ "gp", "gp", "none" ], out => [ "xmm", "none" ] },
emit => '. mov%XXM %AM, %D0',
outs => [ "res", "M" ],
xStore => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "construct Store: Store(ptr, val, mem) = ST ptr,val",
reg_req => { in => [ "gp", "gp", "xmm", "none" ] },
emit => '. mov%XXM %binop',
latency => 2,
xStoreSimple => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "construct Store without index: Store(ptr, val, mem) = ST ptr,val",
reg_req => { in => [ "gp", "gp", "xmm", "none" ] },
ins => [ "base", "index", "val", "mem" ],
emit => '. mov%XXM %S2, %AM',
l_X87toSSE => {
op_flags => "L|F",
- comment => "construct: transfer a value from x87 FPU into a SSE register",
cmp_attr => "return 1;",
arity => 3,
},
l_SSEtoX87 => {
op_flags => "L|F",
- comment => "construct: transfer a value from SSE register to x87 FPU",
cmp_attr => "return 1;",
arity => 3,
},
op_flags => "L|F",
irn_flags => "I",
state => "exc_pinned",
- comment => "store ST0 onto stack",
reg_req => { in => [ "gp", "gp", "none" ] },
emit => '. fstp%XM %AM',
latency => 4,
op_flags => "L|F",
irn_flags => "I",
state => "exc_pinned",
- comment => "load ST0 from stack",
reg_req => { in => [ "gp", "gp", "none" ], out => [ "vf0", "none" ] },
ins => [ "base", "index", "mem" ],
emit => '. fld%XM %AM',
CopyB => {
op_flags => "F|H",
state => "pinned",
- comment => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)",
reg_req => { in => [ "edi", "esi", "ecx", "none" ], out => [ "edi", "esi", "ecx", "none" ] },
outs => [ "DST", "SRC", "CNT", "M" ],
units => [ "GP" ],
CopyB_i => {
op_flags => "F|H",
state => "pinned",
- comment => "implements a memcopy: CopyB(dst, src, mem) == memcpy(dst, src, attr(size))",
reg_req => { in => [ "edi", "esi", "none" ], out => [ "edi", "esi", "none" ] },
outs => [ "DST", "SRC", "M" ],
units => [ "GP" ],
Conv_I2I => {
reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3", "none" ] },
- comment => "construct Conv Int -> Int",
units => [ "GP" ],
mode => $mode_gp,
modified_flags => $status_flags
Conv_I2I8Bit => {
reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "none" ], out => [ "in_r3", "none" ] },
- comment => "construct Conv Int -> Int",
units => [ "GP" ],
mode => $mode_gp,
modified_flags => $status_flags
Conv_I2FP => {
reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "xmm", "none" ] },
- comment => "construct Conv Int -> Floating Point",
latency => 10,
units => [ "SSE" ],
mode => "mode_E",
Conv_FP2I => {
reg_req => { in => [ "gp", "gp", "xmm", "none" ], out => [ "gp", "none" ] },
- comment => "construct Conv Floating Point -> Int",
latency => 10,
units => [ "SSE" ],
mode => $mode_gp,
Conv_FP2FP => {
reg_req => { in => [ "gp", "gp", "xmm", "none" ], out => [ "xmm", "none" ] },
- comment => "construct Conv Floating Point -> Floating Point",
latency => 8,
units => [ "SSE" ],
mode => "mode_E",
CmpCMov => {
irn_flags => "R",
- comment => "construct Conditional Move: CMov(sel, a, b) == sel ? a : b",
reg_req => { in => [ "gp", "gp", "gp", "gp" ], out => [ "in_r4" ] },
latency => 2,
units => [ "GP" ],
PsiCondCMov => {
irn_flags => "R",
- comment => "check if Psi condition tree evaluates to true and move result accordingly",
reg_req => { in => [ "gp", "gp", "gp" ], out => [ "in_r3" ] },
latency => 2,
units => [ "GP" ],
xCmpCMov => {
irn_flags => "R",
- comment => "construct Conditional Move: SSE Compare + int CMov ",
reg_req => { in => [ "xmm", "xmm", "gp", "gp" ], out => [ "in_r4" ] },
latency => 5,
units => [ "SSE" ],
vfCmpCMov => {
irn_flags => "R",
- comment => "construct Conditional Move: x87 Compare + int CMov",
reg_req => { in => [ "vfp", "vfp", "gp", "gp" ], out => [ "in_r4" ] },
latency => 10,
units => [ "VFP" ],
CmpSet => {
irn_flags => "R",
- comment => "construct Set: Set(sel) == sel ? 1 : 0",
reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "eax ebx ecx edx" ] },
latency => 2,
units => [ "GP" ],
PsiCondSet => {
irn_flags => "R",
- comment => "check if Psi condition tree evaluates to true and set result accordingly",
reg_req => { in => [ "gp" ], out => [ "eax ebx ecx edx" ] },
latency => 2,
units => [ "GP" ],
xCmpSet => {
irn_flags => "R",
- comment => "construct Set: SSE Compare + int Set",
reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "eax ebx ecx edx" ] },
latency => 5,
units => [ "SSE" ],
vfCmpSet => {
irn_flags => "R",
- comment => "construct Set: x87 Compare + int Set",
reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "eax ebx ecx edx" ] },
latency => 10,
units => [ "VFP" ],
vfCMov => {
irn_flags => "R",
- comment => "construct x87 Conditional Move: vfCMov(sel, a, b) = sel ? a : b",
reg_req => { in => [ "vfp", "vfp", "vfp", "vfp" ], out => [ "vfp" ] },
latency => 10,
units => [ "VFP" ],
vfadd => {
irn_flags => "R",
- comment => "virtual fp Add: Add(a, b) = Add(b, a) = a + b",
reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
vfmul => {
irn_flags => "R",
- comment => "virtual fp Mul: Mul(a, b) = Mul(b, a) = a * b",
reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
l_vfmul => {
op_flags => "C",
cmp_attr => "return 1;",
- comment => "lowered virtual fp Mul: Mul(a, b) = Mul(b, a) = a * b",
arity => 2,
},
vfsub => {
irn_flags => "R",
- comment => "virtual fp Sub: Sub(a, b) = a - b",
reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
l_vfsub => {
cmp_attr => "return 1;",
- comment => "lowered virtual fp Sub: Sub(a, b) = a - b",
arity => 2,
},
vfdiv => {
- comment => "virtual fp Div: Div(a, b) = a / b",
- reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "vfp" ] },
+ reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "vfp", "none" ] },
outs => [ "res", "M" ],
latency => 20,
units => [ "VFP" ],
l_vfdiv => {
cmp_attr => "return 1;",
- comment => "lowered virtual fp Div: Div(a, b) = a / b",
outs => [ "res", "M" ],
arity => 2,
},
vfprem => {
- comment => "virtual fp Rem: Rem(a, b) = a - Q * b (Q is integer)",
reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "vfp" ] },
latency => 20,
units => [ "VFP" ],
l_vfprem => {
cmp_attr => "return 1;",
- comment => "lowered virtual fp Rem: Rem(a, b) = a - Q * b (Q is integer)",
arity => 2,
},
vfabs => {
irn_flags => "R",
- comment => "virtual fp Abs: Abs(a) = |a|",
reg_req => { in => [ "vfp"], out => [ "vfp" ] },
latency => 2,
units => [ "VFP" ],
vfchs => {
irn_flags => "R",
- comment => "virtual fp Chs: Chs(a) = -a",
reg_req => { in => [ "vfp"], out => [ "vfp" ] },
latency => 2,
units => [ "VFP" ],
vfsin => {
irn_flags => "R",
- comment => "virtual fp Sin: Sin(a) = sin(a)",
reg_req => { in => [ "vfp"], out => [ "vfp" ] },
latency => 150,
units => [ "VFP" ],
vfcos => {
irn_flags => "R",
- comment => "virtual fp Cos: Cos(a) = cos(a)",
reg_req => { in => [ "vfp"], out => [ "vfp" ] },
latency => 150,
units => [ "VFP" ],
vfsqrt => {
irn_flags => "R",
- comment => "virtual fp Sqrt: Sqrt(a) = a ^ 0.5",
reg_req => { in => [ "vfp"], out => [ "vfp" ] },
latency => 30,
units => [ "VFP" ],
vfld => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "virtual fp Load: Load(ptr, mem) = LD ptr -> reg",
reg_req => { in => [ "gp", "gp", "none" ], out => [ "vfp", "none" ] },
outs => [ "res", "M" ],
latency => 2,
vfst => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "virtual fp Store: Store(ptr, val, mem) = ST ptr,val",
reg_req => { in => [ "gp", "gp", "vfp", "none" ] },
latency => 2,
units => [ "VFP" ],
# Conversions
vfild => {
- comment => "virtual fp integer Load: Load(ptr, mem) = iLD ptr -> reg",
reg_req => { in => [ "gp", "gp", "none" ], out => [ "vfp", "none" ] },
outs => [ "res", "M" ],
latency => 4,
l_vfild => {
cmp_attr => "return 1;",
- comment => "lowered virtual fp integer Load: Load(ptr, mem) = iLD ptr -> reg",
outs => [ "res", "M" ],
arity => 2,
},
vfist => {
- comment => "virtual fp integer Store: Store(ptr, val, mem) = iST ptr,val",
reg_req => { in => [ "gp", "gp", "vfp", "fpcw", "none" ] },
latency => 4,
units => [ "VFP" ],
l_vfist => {
cmp_attr => "return 1;",
- comment => "lowered virtual fp integer Store: Store(ptr, val, mem) = iST ptr,val",
arity => 3,
mode => "mode_M",
},
vfldz => {
irn_flags => "R",
- comment => "virtual fp Load 0.0: Ld 0.0 -> reg",
reg_req => { out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
vfld1 => {
irn_flags => "R",
- comment => "virtual fp Load 1.0: Ld 1.0 -> reg",
reg_req => { out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
vfldpi => {
irn_flags => "R",
- comment => "virtual fp Load pi: Ld pi -> reg",
reg_req => { out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
vfldln2 => {
irn_flags => "R",
- comment => "virtual fp Load ln 2: Ld ln 2 -> reg",
reg_req => { out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
vfldlg2 => {
irn_flags => "R",
- comment => "virtual fp Load lg 2: Ld lg 2 -> reg",
reg_req => { out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
vfldl2t => {
irn_flags => "R",
- comment => "virtual fp Load ld 10: Ld ld 10 -> reg",
reg_req => { out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
vfldl2e => {
irn_flags => "R",
- comment => "virtual fp Load ld e: Ld ld e -> reg",
reg_req => { out => [ "vfp" ] },
latency => 4,
units => [ "VFP" ],
op_flags => "c",
irn_flags => "R",
# init_attr => " set_ia32_ls_mode(res, mode);",
- comment => "represents a virtual floating point constant",
reg_req => { out => [ "vfp" ] },
latency => 3,
units => [ "VFP" ],
vfCondJmp => {
state => "pinned",
op_flags => "L|X|Y",
- comment => "represents a virtual floating point compare",
reg_req => { in => [ "gp", "gp", "vfp", "vfp", "none" ], out => [ "none", "none", "eax" ] },
outs => [ "false", "true", "temp_reg_eax" ],
latency => 10,
fadd => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 Add: Add(a, b) = Add(b, a) = a + b",
reg_req => { },
emit => '. fadd%XM %x87_binop',
},
faddp => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 Add: Add(a, b) = Add(b, a) = a + b",
reg_req => { },
emit => '. faddp %x87_binop',
},
fmul => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b",
reg_req => { },
emit => '. fmul%XM %x87_binop',
},
fmulp => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b",
reg_req => { },
emit => '. fmulp %x87_binop',,
},
fsub => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Sub: Sub(a, b) = a - b",
reg_req => { },
emit => '. fsub%XM %x87_binop',
},
fsubp => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Sub: Sub(a, b) = a - b",
reg_req => { },
# see note about gas bugs
emit => '. fsubrp %x87_binop',
op_flags => "R",
rd_constructor => "NONE",
irn_flags => "R",
- comment => "x87 fp SubR: SubR(a, b) = b - a",
reg_req => { },
emit => '. fsubr%XM %x87_binop',
},
op_flags => "R",
rd_constructor => "NONE",
irn_flags => "R",
- comment => "x87 fp SubR: SubR(a, b) = b - a",
reg_req => { },
# see note about gas bugs
emit => '. fsubp %x87_binop',
fprem => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Rem: Rem(a, b) = a - Q * b (Q is integer)",
reg_req => { },
emit => '. fprem1',
},
fpremp => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Rem: Rem(a, b) = a - Q * b (Q is integer)",
reg_req => { },
emit => '. fprem1',
},
fdiv => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Div: Div(a, b) = a / b",
reg_req => { },
emit => '. fdiv%XM %x87_binop',
},
fdivp => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Div: Div(a, b) = a / b",
reg_req => { },
# see note about gas bugs
emit => '. fdivrp %x87_binop',
fdivr => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp DivR: DivR(a, b) = b / a",
reg_req => { },
emit => '. fdivr%XM %x87_binop',
},
fdivrp => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp DivR: DivR(a, b) = b / a",
reg_req => { },
# see note about gas bugs
emit => '. fdivp %x87_binop',
fabs => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Abs: Abs(a) = |a|",
reg_req => { },
emit => '. fabs',
},
fchs => {
op_flags => "R|K",
rd_constructor => "NONE",
- comment => "x87 fp Chs: Chs(a) = -a",
reg_req => { },
emit => '. fchs',
},
fsin => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Sin: Sin(a) = sin(a)",
reg_req => { },
emit => '. fsin',
},
fcos => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Cos: Cos(a) = cos(a)",
reg_req => { },
emit => '. fcos',
},
fsqrt => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp Sqrt: Sqrt(a) = a ^ 0.5",
reg_req => { },
emit => '. fsqrt $',
},
rd_constructor => "NONE",
op_flags => "R|L|F",
state => "exc_pinned",
- comment => "x87 fp Load: Load(ptr, mem) = LD ptr -> reg",
reg_req => { },
emit => '. fld%XM %AM',
},
rd_constructor => "NONE",
op_flags => "R|L|F",
state => "exc_pinned",
- comment => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val",
reg_req => { },
emit => '. fst%XM %AM',
mode => "mode_M",
rd_constructor => "NONE",
op_flags => "R|L|F",
state => "exc_pinned",
- comment => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val",
reg_req => { },
emit => '. fstp%XM %AM',
mode => "mode_M",
fild => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp integer Load: Load(ptr, mem) = iLD ptr -> reg",
reg_req => { },
emit => '. fild%XM %AM',
},
fist => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp integer Store: Store(ptr, val, mem) = iST ptr,val",
reg_req => { },
emit => '. fist%XM %AM',
mode => "mode_M",
fistp => {
op_flags => "R",
rd_constructor => "NONE",
- comment => "x87 fp integer Store: Store(ptr, val, mem) = iST ptr,val",
reg_req => { },
emit => '. fistp%XM %AM',
mode => "mode_M",
fldz => {
op_flags => "R|c|K",
irn_flags => "R",
- comment => "x87 fp Load 0.0: Ld 0.0 -> reg",
reg_req => { },
emit => '. fldz',
},
fld1 => {
op_flags => "R|c|K",
irn_flags => "R",
- comment => "x87 fp Load 1.0: Ld 1.0 -> reg",
reg_req => { },
emit => '. fld1',
},
fldpi => {
op_flags => "R|c|K",
irn_flags => "R",
- comment => "x87 fp Load pi: Ld pi -> reg",
reg_req => { },
emit => '. fldpi',
},
fldln2 => {
op_flags => "R|c|K",
irn_flags => "R",
- comment => "x87 fp Load ln 2: Ld ln 2 -> reg",
reg_req => { },
emit => '. fldln2',
},
fldlg2 => {
op_flags => "R|c|K",
irn_flags => "R",
- comment => "x87 fp Load lg 2: Ld lg 2 -> reg",
reg_req => { },
emit => '. fldlg2',
},
fldl2t => {
op_flags => "R|c|K",
irn_flags => "R",
- comment => "x87 fp Load ld 10: Ld ld 10 -> reg",
reg_req => { },
emit => '. fldll2t',
},
fldl2e => {
op_flags => "R|c|K",
irn_flags => "R",
- comment => "x87 fp Load ld e: Ld ld e -> reg",
reg_req => { },
emit => '. fldl2e',
},
fxch => {
op_flags => "R|K",
- comment => "x87 stack exchange",
reg_req => { },
cmp_attr => "return 1;",
emit => '. fxch %X0',
fpush => {
op_flags => "R|K",
- comment => "x87 stack push",
reg_req => {},
cmp_attr => "return 1;",
emit => '. fld %X0',
fpushCopy => {
op_flags => "R",
- comment => "x87 stack push",
reg_req => { in => [ "vfp"], out => [ "vfp" ] },
cmp_attr => "return 1;",
emit => '. fld %X0',
fpop => {
op_flags => "R|K",
- comment => "x87 stack pop",
reg_req => { },
cmp_attr => "return 1;",
emit => '. fstp %X0',
fcomJmp => {
op_flags => "L|X|Y",
- comment => "floating point compare",
reg_req => { },
},
fcompJmp => {
op_flags => "L|X|Y",
- comment => "floating point compare and pop",
reg_req => { },
},
fcomppJmp => {
op_flags => "L|X|Y",
- comment => "floating point compare and pop twice",
reg_req => { },
},
fcomrJmp => {
op_flags => "L|X|Y",
- comment => "floating point compare reverse",
reg_req => { },
},
fcomrpJmp => {
op_flags => "L|X|Y",
- comment => "floating point compare reverse and pop",
reg_req => { },
},
fcomrppJmp => {
op_flags => "L|X|Y",
- comment => "floating point compare reverse and pop twice",
reg_req => { },
},
xxLoad => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "construct SSE Load: Load(ptr, mem) = LD ptr",
reg_req => { in => [ "gp", "gp", "none" ], out => [ "xmm", "none" ] },
emit => '. movdqu %D0, %AM',
outs => [ "res", "M" ],
xxStore => {
op_flags => "L|F",
state => "exc_pinned",
- comment => "construct Store: Store(ptr, val, mem) = ST ptr,val",
reg_req => { in => [ "gp", "gp", "xmm", "none" ] },
emit => '. movdqu %binop',
units => [ "SSE" ],
my $cmp_attr_func;
my $temp;
my $n_opcodes = 0; # number of opcodes
+my $ARITY_VARIABLE = -1;
+my $ARITY_DYNAMIC = -2;
# for registering additional opcodes
$n_opcodes += $additional_opcodes if (defined($additional_opcodes));
foreach my $op (keys(%nodes)) {
my %n = %{ $nodes{"$op"} };
my $known_mode;
- my $n_res = 0;
my $num_outs = 0;
+ my $out_arity;
my @out_flags;
- # determine arity from in requirements
- $arity = exists($n{"arity"}) ? $n{"arity"} : 0;
- if (exists($n{"reg_req"}) && exists($n{"reg_req"}{"in"})) {
+ # determine arity
+ $arity = 0;
+ if(exists($n{"arity"})) {
+ $arity = $n{"arity"};
+ } elsif (exists($n{"reg_req"}) && exists($n{"reg_req"}{"in"})) {
$arity = scalar(@{ $n{"reg_req"}{"in"} });
+ } elsif (exists($n{"ins"})) {
+ $arity = scalar(@{ $n{"ins"} });
+ }
+ if($arity eq "variable") {
+ $arity = $ARITY_VARIABLE;
+ } elsif($arity eq "dynamic") {
+ $arity = $ARITY_DYNAMIC;
+ }
+
+ # determine out arity
+ $out_arity = 0;
+ if(exists($n{"out_arity"})) {
+ $out_arity = $n{"out_arity"};
+ } elsif (exists($n{"reg_req"}) && exists($n{"reg_req"}{"out"})) {
+ $out_arity = scalar(@{ $n{"reg_req"}{"out"} });
+ } elsif (exists($n{"outs"})) {
+ $out_arity = scalar(@{ $n{"outs"} });
+ }
+ if($out_arity eq "variable") {
+ $out_arity = $ARITY_VARIABLE;
+ } elsif($out_arity eq "dynamic") {
+ $out_arity = $ARITY_DYNAMIC;
}
$orig_op = $op;
$op = $arch."_".$op;
$temp = "";
- # define some proj numbers
+ # define proj numbers and in numbers
if (exists($n{"outs"})) {
undef my @outs;
@outs = @{ $n{"outs"} };
+ if($out_arity >= 0 && scalar(@outs) != $out_arity) {
+ die "Op ${op} has different number of outs and out_arity\n";
+ }
+
$num_outs = $#outs + 1;
push(@obst_proj, "\nenum pn_$op {\n");
undef my @ins;
@ins = @{ $n{"ins"} };
- my $num_ins = $#ins + 1;
+ if($arity >= 0 && scalar(@ins) != $arity) {
+ die "Op ${op} has different number of ins and arity\n";
+ }
push(@obst_proj, "\nenum n_$op {\n");
push(@obst_proj, "};\n");
}
+
+ # determine mode
if (exists($n{"mode"})) {
$known_mode = $n{"mode"};
}
$attr_type = $default_attr_type;
}
+ # determine compare function
my $cmp_attr_func;
if(defined($default_cmp_attr)) {
$cmp_attr_func = "default_cmp_attr";
}
- # create compare attribute function if needed
if (exists($n{"cmp_attr"})) {
my $cmpcode = $n{"cmp_attr"};
if (exists($n{"rd_constructor"}) && $n{"rd_constructor"} =~ /^NONE$/i) {
# we explicitly skip the constructor if the specification entry says NONE
- }
- else {
- $n{"comment"} = "construct $op" if(!exists($n{"comment"}));
- $n{"comment"} =~ s/^"|"$//g; # remove "
- $n{"comment"} = "/* ".$n{"comment"}." */\n";
- push(@obst_constructor, $n{"comment"});
+ } else {
+ my $comment = $n{"comment"};
+ if(!exists($n{"comment"})) {
+ $comment = "construct ${orig_op} node";
+ }
+ $comment =
+ "/**\n".
+ " * ${comment}\n".
+ " */\n";
+
+ push(@obst_constructor, $comment);
# create constructor head
my $complete_args = "";
- my $arg_names = "";
$temp = "";
$temp = "ir_node *new_rd_$op(dbg_info *db, ir_graph *irg, ir_node *block";
- if (!exists($n{"args"}) || $n{"args"} =~ /^DEFAULT$/i) { # default args
- if ($arity !~ /^\d+$/) {
- print "DEFAULT args require numeric arity (0, 1, 2, ...)! Ignoring op $orig_op!\n";
- next;
+ if (!exists($n{"args"})) { # default args
+ if ($arity == $ARITY_VARIABLE) {
+ $complete_args = ", int arity, ir_node *in[]";
+ } elsif ($arity == $ARITY_DYNAMIC) {
+ $complete_args = "";
+ } else {
+ for (my $i = 0; $i < $arity; $i++) {
+ my $opname = "op${i}";
+ if (exists($n{"ins"})) {
+ my @ins = @{ $n{"ins"} };
+ $opname = $ins[$i];
+ }
+
+ $complete_args .= ", ir_node *${opname}";
+ }
}
- for (my $i = 1; $i <= $arity; $i++) {
- $complete_args .= ", ir_node *op".$i;
- $arg_names .= ", op".$i;
+ if ($out_arity == $ARITY_VARIABLE) {
+ $complete_args .= ", int n_res";
}
+
if (!defined($known_mode)) {
$complete_args .= ", ir_mode *mode";
- $arg_names .= ", mode";
}
- }
- else { # user defined args
+ } else { # user defined args
for my $href (@{ $n{"args"} }) {
$href->{"type"} .= " " if ($href->{"type"} !~ / [*]?$/); # put a space between name and type if there is none at the end
$complete_args .= ", ".$href->{"type"}.$href->{"name"};
- $arg_names .= ", ".$href->{"name"};
}
}
$complete_args .= ", ".$n{"attr"};
}
- # $complete_args = substr($complete_args, 2);
$temp .= "$complete_args)";
- push(@obst_constructor, $temp." {\n");
- push(@obst_header, $n{"comment"});
+ push(@obst_constructor, $temp."\n{\n");
+ push(@obst_header, $comment);
push(@obst_header, $temp.";\n");
# emit constructor code
- if (!exists($n{"rd_constructor"}) || $n{"rd_constructor"} =~ /^DEFAULT$/i) { # default constructor
- if ($arity !~ /^\d+$/) {
- print "DEFAULT rd_constructor requires numeric arity! Ignoring op $orig_op!\n";
- next;
+ if (!exists($n{"rd_constructor"})) { # default constructor
+ $temp = "\tir_node *res;\n";
+ $temp .= "\tir_op *op = op_${op};\n";
+ $temp .= "\tint flags = 0;\n";
+
+ if($arity == $ARITY_DYNAMIC) {
+ $temp .= "\tint arity = 0;\n";
+ $temp .= "\tir_node **in = NULL;\n";
+ } elsif($arity == $ARITY_VARIABLE) {
+ } else {
+ $temp .= "\tint arity = $arity;\n";
+ if($arity > 0) {
+ $temp .= "\tir_node *in[$arity];\n";
+ } else {
+ $temp .= "\tir_node **in = NULL;\n";
+ }
+ }
+ if($out_arity == $ARITY_DYNAMIC) {
+ $temp .= "\tint n_res = 0;\n";
+ } elsif($out_arity == $ARITY_VARIABLE) {
+ } else {
+ $temp .= "\tint n_res = ${out_arity};\n";
+ }
+
+ my $latency = $n{"latency"};
+ if (!defined($latency)) {
+ $latency = 1;
}
+ $temp .= "\tunsigned latency = ${latency};\n";
- $temp = "\tir_node *res;\n";
- $temp .= "\tir_node *in[$arity];\n" if ($arity > 0);
- $temp .= "\tint flags = 0;\n";
- $temp .= "\t${attr_type} *attr;\n" if (exists($n{"init_attr"}));
+ if (defined($known_mode)) {
+ $temp .= "\tir_mode *mode = ${known_mode};\n";
+ }
- my $exec_units = "NULL";
# set up static variables for cpu execution unit assigments
if (exists($n{"units"})) {
$temp .= gen_execunit_list_initializer($n{"units"});
- $exec_units = "_exec_units";
+ } else {
+ $temp .= "\tstatic const be_execution_unit_t ***exec_units = NULL;\n";
}
undef my $in_req_var;
@out = @{ $req{"out"} } if exists(($req{"out"}));
if (@in) {
- $in_req_var = "_in_req_$op";
- $temp .= "\tstatic const arch_register_req_t *".$in_req_var."[] =\n";
+ if($arity >= 0 && scalar(@in) != $arity) {
+ die "Arity and number of in requirements don't match for ${op}\n";
+ }
+
+ $temp .= "\tstatic const arch_register_req_t *in_reqs[] =\n";
$temp .= "\t{\n";
for ($idx = 0; $idx <= $#in; $idx++) {
$temp .= "\t\t&".$op."_reg_req_in_".$idx.",\n";
}
$temp .= "\t};\n";
+ } else {
+ if($arity > 0) {
+ die "need in requirements for ${op}\n";
+ }
+ $temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n";
}
if (@out) {
- $out_req_var = "_out_req_$op";
+ if($out_arity >= 0 && scalar(@out) != $out_arity) {
+ die "Out-Arity and number of out requirements don't match for ${op}\n";
+ }
- $temp .= "\tstatic const arch_register_req_t *".$out_req_var."[] =\n";
+ $temp .= "\tstatic const arch_register_req_t *out_reqs[] =\n";
$temp .= "\t{\n";
for ($idx = 0; $idx <= $#out; $idx++) {
$temp .= "\t\t&".$op."_reg_req_out_".$idx.",\n";
}
$temp .= "\t};\n";
+ } else {
+ if($out_arity > 0) {
+ die "need out requirements for ${op}\n";
+ }
+ $temp .= "\tstatic const arch_register_req_t **out_reqs = NULL;\n";
}
+ } else {
+ $temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n";
+ $temp .= "\tstatic const arch_register_req_t **out_reqs = NULL;\n";
+ }
+ if(exists($n{"init_attr"})) {
+ $temp .= "\t${attr_type} *attr;\n";
}
$temp .= "\n";
- $temp .= "\tassert(op_$op != NULL);\n\n";
- for (my $i = 1; $i <= $arity; $i++) {
- $temp .= "\tin[".($i - 1)."] = op".$i.";\n";
+ if($arity > 0) {
+ $temp .= "\t/* construct in array */\n";
+ for (my $i = 0; $i < $arity; $i++) {
+ my $opname = "op${i}";
+ if (exists($n{"ins"})) {
+ my @ins = @{ $n{"ins"} };
+ $opname = $ins[$i];
+ }
+
+ $temp .= "\tin[${i}] = ${opname};\n";
+ }
+ $temp .= "\n";
}
# set flags
if (exists($n{"irn_flags"})) {
+ $temp .= "\t/* flags */\n";
foreach my $flag (split(/\|/, $n{"irn_flags"})) {
if ($flag eq "R") {
- $temp .= "\tflags |= arch_irn_flags_rematerializable; /* op can be easily recalculated */\n";
+ $temp .= "\tflags |= arch_irn_flags_rematerializable;\n";
+ } elsif ($flag eq "N") {
+ $temp .= "\tflags |= arch_irn_flags_dont_spill;\n";
+ } elsif ($flag eq "I") {
+ $temp .= "\tflags |= arch_irn_flags_ignore;\n";
+ } elsif ($flag eq "S") {
+ $temp .= "\tflags |= arch_irn_flags_modify_sp;\n";
}
- elsif ($flag eq "N") {
- $temp .= "\tflags |= arch_irn_flags_dont_spill; /* op is NOT spillable */\n";
- }
- elsif ($flag eq "I") {
- $temp .= "\tflags |= arch_irn_flags_ignore; /* ignore op for register allocation */\n";
- }
- elsif ($flag eq "S") {
- $temp .= "\tflags |= arch_irn_flags_modify_sp; /* op modifies stack pointer */\n";
- }
- }
- }
-
- my $in_param;
- my $out_param;
- # allocate memory and set pointer to register requirements
- if (exists($n{"reg_req"})) {
- my %req = %{ $n{"reg_req"} };
-
- undef my @in;
- @in = @{ $req{"in"} } if (exists($req{"in"}));
- undef my @out;
- @out = @{ $req{"out"} } if exists(($req{"out"}));
-
- if (@in) {
- $in_param = $in_req_var;
}
- else {
- $in_param = "NULL";
- }
-
- if (@out) {
- $n_res = $#out + 1;
- $out_param = "$out_req_var, $exec_units, $n_res";
- }
- else {
- $out_param = "NULL, $exec_units, 0";
- }
- }
- else {
- $in_param = "NULL";
- $out_param = "NULL, $exec_units, 0";
- }
- $temp .= "\n\t/* create node */\n";
-
- my $latency = 1;
- if (exists($n{"latency"})) {
- $latency = $n{"latency"};
+ $temp .= "\n";
}
- my $mode = "mode";
- if (defined($known_mode)) {
- $mode = $known_mode;
- }
- $temp .= "\tres = new_ir_node(db, irg, block, op_$op, $mode, $arity, ".($arity > 0 ? "in" : "NULL").");\n";
+ $temp .= "\t/* create node */\n";
+ $temp .= "\tassert(op != NULL);\n";
+ $temp .= "\tres = new_ir_node(db, irg, block, op, mode, arity, in);\n";
+ $temp .= "\n";
- $temp .= "\n\t/* init node attributes */\n";
- $temp .= "\tinit_$arch\_attributes(res, flags, $in_param, $out_param, $latency);\n";
+ $temp .= "\t/* init node attributes */\n";
+ $temp .= "\tinit_$arch\_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n";
+ $temp .= "\n";
# set flags for outs
if ($#out_flags >= 0) {
- $temp .= "\n\t/* set flags for outs */\n";
+ $temp .= "\t/* set flags for outs */\n";
for (my $idx = 0; $idx <= $#out_flags; $idx++) {
my $flags = "";
my $prefix = "";
$temp .= "\tset_$arch\_out_flags(res, $flags, $idx);\n";
}
+ $temp .= "\n";
}
$temp .= $n{"init_attr"}."\n";
}
- $temp .= "\n\t/* optimize node */\n";
+ $temp .= "\t/* optimize node */\n";
$temp .= "\tres = optimize_node(res);\n";
- $temp .= "\tirn_vrfy_irg(res, irg);\n\n";
+ $temp .= "\tirn_vrfy_irg(res, irg);\n";
+ $temp .= "\n";
- $temp .= "\n\treturn res;\n";
+ $temp .= "\treturn res;\n";
push(@obst_constructor, $temp);
}
}
$n_opcodes++;
+ my $n_res = $out_arity;
+ if($n_res < 0) {
+ $n_res = "20"; # hacky....
+ }
$temp = "\top_$op = new_ir_op(cur_opcode + iro_$op, \"$op\", op_pin_state_".$n{"state"}.", ".$n{"op_flags"};
$temp .= "|M, ".translate_arity($arity).", 0, sizeof(${attr_type}) + $n_res * sizeof(arch_register_t *), &ops);\n";
push(@obst_new_irop, $temp);
else {
return "oparity_any";
}
- }
- else {
- return "oparity_".$arity;
+ } elsif ($arity == $ARITY_VARIABLE) {
+ return "oparity_variable";
+ } elsif ($arity == $ARITY_DYNAMIC) {
+ return "oparity_dynamic";
+ } else {
+ die "Unknown arity $arity";
}
}
# prepare the 2-dim array init
foreach my $key (keys(%init)) {
- $ret .= "\tstatic const be_execution_unit_t *_allowed_units_".$key."[] =\n";
+ $ret .= "\tstatic const be_execution_unit_t *allowed_units_".$key."[] =\n";
$ret .= "\t{\n";
foreach (@{ $init{"$key"} }) {
$ret .= "$_,\n";
}
$ret .= "\t\tNULL\n";
$ret .= "\t};\n";
- $ret2 .= "\t\t_allowed_units_$key,\n";
+ $ret2 .= "\t\tallowed_units_$key,\n";
}
$ret2 .= "\t\tNULL\n";
- $ret .= "\tstatic const be_execution_unit_t **_exec_units[] =\n";
+ $ret .= "\tstatic const be_execution_unit_t **exec_units[] =\n";
$ret .= "\t{\n";
$ret .= $ret2;
$ret .= "\t};\n";