# Licensed to the .NET Foundation under one or more agreements.
# The .NET Foundation licenses this file to you under the MIT license.
# See the LICENSE file in the project root for more information.
#
# GENREFOPS.PL
#
# PERL script used to generate the numbering of the reference opcodes
#
#use strict 'vars';
#use strict 'subs';
#use strict 'refs';
my $ret = 0;
my %oneByte;
my %twoByte;
my %controlFlow;
my @singleByteArg;
my %stackbehav;
my %opcodetype;
my %operandtype;
my %opcodes;
my $popstate;
my $pushstate;
$ctrlflowcount = 0;
$count = 0;
my @lowercaseAlphabet = ('a'..'z','0'..'9');
my %upcaseAlphabet = ();
foreach $letter (@lowercaseAlphabet) {
$j = $letter;
$j=~tr/a-z/A-Z/;
$upcaseAlphabet{$letter}=$j;
}
open (OPCODE, "opcode.def") or die "Couldn't open opcode.def: $!\n";
open (OUTPUT, ">OpCodes.cs") or die "Couldn't open OpCodes.cs: $!\n";
open (FCOUTPUT, ">FlowControl.cs") or die "Couldn't open FlowControl.cs: $!\n";
open (SOUTPUT, ">StackBehaviour.cs") or die "Couldn't open StackBehaviour.cs: $!\n";
open (OCOUTPUT, ">OpCodeType.cs") or die "Couldn't open OpCodeType.cs: $!\n";
open (OPOUTPUT, ">OperandType.cs") or die "Couldn't open OprandType.cs: $!\n";
print OUTPUT "/*============================================================\n";
print OUTPUT "**\n";
print OUTPUT "**Class: OpCodes\n";
print OUTPUT "**\n";
print OUTPUT "**Purpose: Exposes all of the il instructions supported by the runtime.\n";
print OUTPUT "**\n";
print OUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n";
print OUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n";
print OUTPUT "**See the LICENSE file in the project root for more information.\n";
print OUTPUT "**\n";
print OUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n";
print OUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n";
print OUTPUT "============================================================*/\n";
print OUTPUT "namespace System.Reflection.Emit {\n\n";
print OUTPUT "using System;\n\n";;
print OUTPUT "public class OpCodes {\n\n";;
print OUTPUT "/// \n";
print OUTPUT "/// \n";
print OUTPUT "/// The IL instruction opcodes supported by the\n";
print OUTPUT "/// runtime. The IL Instruction Specification describes each\n";
print OUTPUT "/// Opcode.\n";
print OUTPUT "/// \n";
print OUTPUT "/// \n";
print OUTPUT "/// \n";
print OUTPUT "\n";
print OUTPUT "\tprivate OpCodes() { \n\t}\n\n";
print FCOUTPUT "/*============================================================\n";
print FCOUTPUT "**\n";
print FCOUTPUT "**Class: FlowControl\n";
print FCOUTPUT "**\n";
print FCOUTPUT "**Purpose: Exposes FlowControl Attribute of IL .\n";
print FCOUTPUT "**\n";
print FCOUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n";
print FCOUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n";
print FCOUTPUT "**See the LICENSE file in the project root for more information.\n";
print FCOUTPUT "**\n";
print FCOUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n";
print FCOUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n";
print FCOUTPUT "============================================================*/\n";
print FCOUTPUT "namespace System.Reflection.Emit {\n\n";
print FCOUTPUT "using System;\n\n";
print FCOUTPUT "public enum FlowControl\n{\n\n";
print SOUTPUT "/*============================================================\n";
print SOUTPUT "**\n";
print SOUTPUT "**Class: StackBehaviour\n";
print SOUTPUT "**\n";
print SOUTPUT "**Purpose: Exposes StackBehaviour Attribute of IL .\n";
print SOUTPUT "**\n";
print SOUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n";
print SOUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n";
print SOUTPUT "**See the LICENSE file in the project root for more information.\n";
print SOUTPUT "**\n";
print SOUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n";
print SOUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n";
print SOUTPUT "============================================================*/\n";
print SOUTPUT "namespace System.Reflection.Emit {\n\n";
print SOUTPUT "using System;\n\n";
print SOUTPUT "public enum StackBehaviour\n{\n\n";
print OCOUTPUT "/*============================================================\n";
print OCOUTPUT "**\n";
print OCOUTPUT "**Class: OpCodeType\n";
print OCOUTPUT "**\n";
print OCOUTPUT "**Purpose: Exposes OpCodeType Attribute of IL .\n";
print OCOUTPUT "**\n";
print OCOUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n";
print OCOUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n";
print OCOUTPUT "**See the LICENSE file in the project root for more information.\n";
print OCOUTPUT "**\n";
print OCOUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n";
print OCOUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n";
print OCOUTPUT "============================================================*/\n";
print OCOUTPUT "namespace System.Reflection.Emit {\n\n";
print OCOUTPUT "using System;\n\n";
print OCOUTPUT "public enum OpCodeType\n{\n\n";
print OPOUTPUT "/*============================================================\n";
print OPOUTPUT "**\n";
print OPOUTPUT "**Class: OperandType\n";
print OPOUTPUT "**\n";
print OPOUTPUT "**Purpose: Exposes OperandType Attribute of IL .\n";
print OPOUTPUT "**\n";
print OPOUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n";
print OPOUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n";
print OPOUTPUT "**See the LICENSE file in the project root for more information.\n";
print OPOUTPUT "**\n";
print OPOUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n";
print OPOUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n";
print OPOUTPUT "============================================================*/\n";
print OPOUTPUT "namespace System.Reflection.Emit {\n\n";
print OPOUTPUT "using System;\n\n";
print OPOUTPUT "public enum OperandType\n{\n\n";
while ()
{
# Process only OPDEF(....) lines
if (/OPDEF\(\s*/)
{
chop; # Strip off trailing CR
s/^OPDEF\(\s*//; # Strip off "OP("
s/\)$//; # Strip off ")" at end
s/,\s*/,/g; # Remove whitespace
# Split the line up into its basic parts
($enumname, $stringname, $pop, $push, $operand, $type, $size, $s1, $s2, $ctrl) = split(/,/);
$s1 =~ s/0x//;
$s1 = hex($s1);
$s2 =~ s/0x//;
$s2 = hex($s2);
if ($size == 0)
{
next;
}
next if ($enumname =~ /UNUSED/);
#Remove the prefix
$enumname=~s/CEE_//g;
#Convert name to our casing convention
$enumname=~tr/A-Z/a-z/;
$enumname=~s/^(.)/\u$1/g;
$enumname=~s/_(.)/_\u$1/g;
#Convert pop to our casing convention
$pop=~tr/A-Z/a-z/;
$pop=~s/^(.)/\u$1/g;
$pop=~s/_(.)/_\u$1/g;
#Convert push to our casing convention
$push=~tr/A-Z/a-z/;
$push=~s/^(.)/\u$1/g;
$push=~s/_(.)/_\u$1/g;
#Convert operand to our casing convention
#$operand=~tr/A-Z/a-z/;
#$operand=~s/^(.)/\u$1/g;
#$operand=~s/_(.)/_\u$1/g;
#Remove the I prefix on type
$type=~s/I//g;
#Convert Type to our casing convention
$type=~tr/A-Z/a-z/;
$type=~s/^(.)/\u$1/g;
$type=~s/_(.)/_\u$1/g;
#Convert ctrl to our casing convention
$ctrl=~tr/A-Z/a-z/;
$ctrl=~s/^(.)/\u$1/g;
$ctrl=~s/_(.)/_\u$1/g;
# Make a list of the flow Control type
# Make a list of the opcodes and there values
if ($opcodes{$enumname})
{
}
else
{
if ($size == 1)
{
$opcodes{$enumname} = $s2;
}
else
{
$opcodes{$enumname} = ($s2 + 256 * $s1);
}
}
#Make a list of the instructions which only take one-byte arguments
if ($enumname =~ /^.*_S$/) {
#but exclude the deprecated expressions (sometimes spelled "depricated")
if (!($enumname=~/^Depr.cated.*/)) {
my $caseStatement = sprintf("\t\tcase %-20s: \n", $enumname);
push(@singleByteArg, $caseStatement);
}
}
#make a list of the control Flow Types
if ($controlFlow{$ctrl})
{
#printf("DUPE Control Flow\n");
}
else
{
$controlFlow{$ctrl} = $ctrlflowcount;
$ctrlflowcount++;
}
$ctrlflowcount = 0;
#make a list of the control Flow Types
$pop=~s/\+/_/g;
if ($stackbehav{$pop})
{
#printf("DUPE Control Flow\n");
}
else
{
$stackbehav{$pop} = $ctrlflowcount;
$ctrlflowcount++;
}
#make a list of the control Flow Types
$push=~s/\+/_/g;
if ($stackbehav{$push})
{
#printf("DUPE Control Flow\n");
}
else
{
$stackbehav{$push} = $ctrlflowcount;
$ctrlflowcount++;
}
#make a list of operand types
if ($operandtype{$operand})
{
#printf("DUPE Control Flow\n");
}
else
{
$operandtype{$operand} = $ctrlflowcount;
$ctrlflowcount++;
}
#make a list of opcode types
if ($opcodetype{$type})
{
#printf("DUPE Control Flow\n");
}
else
{
$opcodetype{$type} = $ctrlflowcount;
$ctrlflowcount++;
}
print "$enumname\n";
print "$stringname\n";
if ($stringname eq "arglist")
{
print "This is arglist----------\n";
}
my $line = sprintf("\tpublic static readonly OpCode %-20s = ", $enumname);
if ($size == 1)
{
$line .= sprintf("new OpCode(%s, StackBehaviour.%s, StackBehaviour.%s, OperandType.%s, OpCodeType.%s, %u, (byte)0x%x, (byte)0x%x, FlowControl.%s, " , $stringname, $pop, $push, $operand, $type, $size, $s1, $s2, $ctrl);
if ($ctrl eq "Return" || $ctrl eq "Branch" || $ctrl eq "Throw" || $stringname eq "\"jmp\"" || $stringname eq "\"jmpi\"")
{
$line .= sprintf("true, ");
}
else
{
$line .= sprintf("false, ");
}
$popstate = 0;
if($pop eq "Pop0" || $pop eq "Varpop")
{
$popstate = 0;
}
elsif ($pop eq "Pop1" || $pop eq "Popi" || $pop eq "Popref")
{
$popstate = $popstate -1;
}
elsif ($pop eq "Pop1_pop1" || $pop eq "Popi_pop1" || $pop eq "Popi_popi" || $pop eq "Popi_popi8" || $pop eq "Popi_popr4" || $pop eq "Popi_popr8" || $pop eq "Popref_pop1" || $pop eq "Popref_popi")
{
$popstate = $popstate -2;
}
elsif ($pop eq "Popi_popi_popi" || $pop eq "Popref_popi_popi" || $pop eq "Popref_popi_popi8" || $pop eq "Popref_popi_popr4" || $pop eq "Popref_popi_popr8" || $pop eq "Popref_popi_popref")
{
$popstate = $popstate -3;
}
if ($push eq "Push1" || $push eq "Pushi" ||$push eq "Pushi8" ||$push eq "Pushr4" ||$push eq "Pushr8" ||$push eq "Pushref")
{
$popstate = $popstate + 1;
}
elsif($push eq "Push1_push1")
{
$popstate = $popstate + 2;
}
$line .= sprintf(" $popstate");
$line .= sprintf(");\n\n");
if ($oneByte{$s2})
{
printf("Error opcode 0x%x already defined!\n", $s2);
print " Old = $oneByte{$s2}";
print " New = $line";
$ret = -1;
}
$oneByte{$s2} = $line;
}
elsif ($size == 2)
{
if ($twoByte{$s2})
{
printf("Error opcode 0x%x%x already defined!\n", $s1, $s2);
print " Old = $oneByte{$s2}";
print " New = $line";
$ret = -1;
}
$line .= sprintf("new OpCode(%s, StackBehaviour.%s, StackBehaviour.%s, OperandType.%s, OpCodeType.%s, %u, (byte)0x%x, (byte)0x%x, FlowControl.%s, " , $stringname, $pop, $push, $operand, $type, $size, $s1, $s2, $ctrl);
if ($ctrl eq "Return" || $ctrl eq "Branch" || $ctrl eq "Throw" || $stringname eq "\"jmp\"" || $stringname eq "\"jmpi\"")
{
$line .= sprintf("true, ");
}
else
{
$line .= sprintf("false, ");
}
$popstate = 0;
if($pop eq "Pop0" || $pop eq "Varpop")
{
$popstate = 0;
}
elsif($pop eq "Pop1" || $pop eq "Popi" || $pop eq "Popref")
{
$popstate = $popstate -1;
}
elsif ($pop eq "Pop1_pop1" || $pop eq "Popi_pop1" || $pop eq "Popi_popi" || $pop eq "Popi_popi8" || $pop eq "Popi_popr4" || $pop eq "Popi_popr8" || $pop eq "Popref_pop1" || $pop eq "Popref_popi")
{
$popstate = $popstate -2;
}
elsif ($pop eq "Popi_popi_popi" || $pop eq "Popref_popi_popi" || $pop eq "Popref_popi_popi8" || $pop eq "Popref_popi_popr4" || $pop eq "Popref_popi_popr8" || $pop eq "Popref_popi_popref")
{
$popstate = $popstate -3;
}
if ($push eq "Push1" || $push eq "Pushi" ||$push eq "Pushi8" ||$push eq "Pushr4" ||$push eq "Pushr8" ||$push eq "Pushref")
{
$popstate = $popstate + 1;
}
elsif($push eq "Push1_push1")
{
$popstate = $popstate + 2;
}
$line .= sprintf(" $popstate");
$line .= sprintf(");\n\n");
$twoByte{$s2 + 256 * $s1} = $line;
}
else
{
$line .= "\n";
push(@deprecated, $line);
}
$count++;
}
}
#Write out the Flow Control class
$ctrlflowcount = 0;
foreach $key (sort {$a cmp $b} keys (%controlFlow))
{
print FCOUTPUT "\t$key";
print FCOUTPUT "\t= $ctrlflowcount,\n";
$ctrlflowcount++;
}
#end the flowcontrol class
print FCOUTPUT "}\n}";
#Write out the StackBehaviour class
$ctrlflowcount = 0;
foreach $key (sort {$a cmp $b} keys (%stackbehav))
{
print SOUTPUT "\t$key";
print SOUTPUT "\t= $ctrlflowcount,\n";
$ctrlflowcount++;
}
#end the StackBehaviour class
print SOUTPUT "}\n}";
$ctrlflowcount = 0;
foreach $key (sort {$a cmp $b} keys (%opcodetype))
{
print OCOUTPUT "\t$key";
print OCOUTPUT "\t= $ctrlflowcount,\n";
$ctrlflowcount++;
}
#end the OpCodeTYpe class
print OCOUTPUT "}\n}";
$ctrlflowcount = 0;
foreach $key (sort {$a cmp $b} keys (%operandtype))
{
print OPOUTPUT "\t$key";
print OPOUTPUT "\t= $ctrlflowcount,\n";
$ctrlflowcount++;
}
#end the OperandType class
print OPOUTPUT "}\n}";
my $opcode;
my $lastOp = -1;
foreach $opcode (sort {$a <=> $b} keys(%oneByte)) {
printf("***** GAP %d instrs ****\n", $opcode - $lastOp) if ($lastOp + 1 != $opcode && $lastOp > 0);
print OUTPUT $oneByte{$opcode};
$lastOp = $opcode;
}
$lastOp = -1;
foreach $opcode (sort {$a <=> $b} keys(%twoByte)) {
printf("***** GAP %d instrs ****\n", $opcode - $lastOp) if ($lastOp + 1 != $opcode && $lastOp > 0);
print OUTPUT $twoByte{$opcode};
$lastOp = $opcode;
}
print OUTPUT "\n\n\tpublic static bool TakesSingleByteArgument(OpCode inst)\n\t{\n";
print OUTPUT"\t\tswitch(inst.m_operand)\n\t\t{\n";
print OUTPUT "\t\t\tcase OperandType.ShortInlineBrTarget :\n";
print OUTPUT "\t\t\tcase OperandType.ShortInlineI :\n";
print OUTPUT "\t\t\tcase OperandType.ShortInlineVar :\n";
print OUTPUT "\t\t\treturn true;\n";
print OUTPUT "\t\t};\n";
print OUTPUT "\t\treturn false;\n";
print OUTPUT "\t}\n";
print OUTPUT "}\n}";
exit($ret);