435 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			435 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| #!/usr/local/bin/perl
 | |
| 
 | |
| package alpha;
 | |
| use Carp qw(croak cluck);
 | |
| 
 | |
| $label="100";
 | |
| 
 | |
| $n_debug=0;
 | |
| $smear_regs=1;
 | |
| $reg_alloc=1;
 | |
| 
 | |
| $align="3";
 | |
| $com_start="#";
 | |
| 
 | |
| sub main'asm_init_output { @out=(); }
 | |
| sub main'asm_get_output { return(@out); }
 | |
| sub main'get_labels { return(@labels); }
 | |
| sub main'external_label { push(@labels,@_); }
 | |
| 
 | |
| # General registers
 | |
| 
 | |
| %regs=(	'r0',	'$0',
 | |
| 	'r1',	'$1',
 | |
| 	'r2',	'$2',
 | |
| 	'r3',	'$3',
 | |
| 	'r4',	'$4',
 | |
| 	'r5',	'$5',
 | |
| 	'r6',	'$6',
 | |
| 	'r7',	'$7',
 | |
| 	'r8',	'$8',
 | |
| 	'r9',	'$22',
 | |
| 	'r10',	'$23',
 | |
| 	'r11',	'$24',
 | |
| 	'r12',	'$25',
 | |
| 	'r13',	'$27',
 | |
| 	'r14',	'$28',
 | |
| 	'r15',	'$21', # argc == 5
 | |
| 	'r16',	'$20', # argc == 4
 | |
| 	'r17',	'$19', # argc == 3
 | |
| 	'r18',	'$18', # argc == 2
 | |
| 	'r19',	'$17', # argc == 1
 | |
| 	'r20',	'$16', # argc == 0
 | |
| 	'r21',	'$9',  # save 0
 | |
| 	'r22',	'$10', # save 1
 | |
| 	'r23',	'$11', # save 2
 | |
| 	'r24',	'$12', # save 3
 | |
| 	'r25',	'$13', # save 4
 | |
| 	'r26',	'$14', # save 5
 | |
| 
 | |
| 	'a0',	'$16',
 | |
| 	'a1',	'$17',
 | |
| 	'a2',	'$18',
 | |
| 	'a3',	'$19',
 | |
| 	'a4',	'$20',
 | |
| 	'a5',	'$21',
 | |
| 
 | |
| 	's0',	'$9',
 | |
| 	's1',	'$10',
 | |
| 	's2',	'$11',
 | |
| 	's3',	'$12',
 | |
| 	's4',	'$13',
 | |
| 	's5',	'$14',
 | |
| 	'zero',	'$31',
 | |
| 	'sp',	'$30',
 | |
| 	);
 | |
| 
 | |
| $main'reg_s0="r21";
 | |
| $main'reg_s1="r22";
 | |
| $main'reg_s2="r23";
 | |
| $main'reg_s3="r24";
 | |
| $main'reg_s4="r25";
 | |
| $main'reg_s5="r26";
 | |
| 
 | |
| @reg=(  '$0', '$1' ,'$2' ,'$3' ,'$4' ,'$5' ,'$6' ,'$7' ,'$8',
 | |
| 	'$22','$23','$24','$25','$20','$21','$27','$28');
 | |
| 
 | |
| 
 | |
| sub main'sub	{ &out3("subq",@_); }
 | |
| sub main'add	{ &out3("addq",@_); }
 | |
| sub main'mov	{ &out3("bis",$_[0],$_[0],$_[1]); }
 | |
| sub main'or	{ &out3("bis",@_); }
 | |
| sub main'bis	{ &out3("bis",@_); }
 | |
| sub main'br	{ &out1("br",@_); }
 | |
| sub main'ld	{ &out2("ldq",@_); }
 | |
| sub main'st	{ &out2("stq",@_); }
 | |
| sub main'cmpult	{ &out3("cmpult",@_); }
 | |
| sub main'cmplt	{ &out3("cmplt",@_); }
 | |
| sub main'bgt	{ &out2("bgt",@_); }
 | |
| sub main'ble	{ &out2("ble",@_); }
 | |
| sub main'blt	{ &out2("blt",@_); }
 | |
| sub main'mul	{ &out3("mulq",@_); }
 | |
| sub main'muh	{ &out3("umulh",@_); }
 | |
| 
 | |
| $main'QWS=8;
 | |
| 
 | |
| sub main'asm_add
 | |
| 	{
 | |
| 	push(@out,@_);
 | |
| 	}
 | |
| 
 | |
| sub main'asm_finish
 | |
| 	{
 | |
| 	&main'file_end();
 | |
| 	print &main'asm_get_output();
 | |
| 	}
 | |
| 
 | |
| sub main'asm_init
 | |
| 	{
 | |
| 	($type,$fn)=@_;
 | |
| 	$filename=$fn;
 | |
| 
 | |
| 	&main'asm_init_output();
 | |
| 	&main'comment("Don't even think of reading this code");
 | |
| 	&main'comment("It was automatically generated by $filename");
 | |
| 	&main'comment("Which is a perl program used to generate the alpha assember.");
 | |
| 	&main'comment("eric <eay\@cryptsoft.com>");
 | |
| 	&main'comment("");
 | |
| 
 | |
| 	$filename =~ s/\.pl$//;
 | |
| 	&main'file($filename);
 | |
| 	}
 | |
| 
 | |
| sub conv
 | |
| 	{
 | |
| 	local($r)=@_;
 | |
| 	local($v);
 | |
| 
 | |
| 	return($regs{$r}) if defined($regs{$r});
 | |
| 	return($r);
 | |
| 	}
 | |
| 
 | |
| sub main'QWPw
 | |
| 	{
 | |
| 	local($off,$reg)=@_;
 | |
| 
 | |
| 	return(&main'QWP($off*8,$reg));
 | |
| 	}
 | |
| 
 | |
| sub main'QWP
 | |
| 	{
 | |
| 	local($off,$reg)=@_;
 | |
| 
 | |
| 	$ret="$off(".&conv($reg).")";
 | |
| 	return($ret);
 | |
| 	}
 | |
| 
 | |
| sub out3
 | |
| 	{
 | |
| 	local($name,$p1,$p2,$p3)=@_;
 | |
| 
 | |
| 	$p1=&conv($p1);
 | |
| 	$p2=&conv($p2);
 | |
| 	$p3=&conv($p3);
 | |
| 	push(@out,"\t$name\t");
 | |
| 	$l=length($p1)+1;
 | |
| 	push(@out,$p1.",");
 | |
| 	$ll=3-($l+9)/8;
 | |
| 	$tmp1=sprintf("\t" x $ll);
 | |
| 	push(@out,$tmp1);
 | |
| 
 | |
| 	$l=length($p2)+1;
 | |
| 	push(@out,$p2.",");
 | |
| 	$ll=3-($l+9)/8;
 | |
| 	$tmp1=sprintf("\t" x $ll);
 | |
| 	push(@out,$tmp1);
 | |
| 
 | |
| 	push(@out,&conv($p3)."\n");
 | |
| 	}
 | |
| 
 | |
| sub out2
 | |
| 	{
 | |
| 	local($name,$p1,$p2,$p3)=@_;
 | |
| 
 | |
| 	$p1=&conv($p1);
 | |
| 	$p2=&conv($p2);
 | |
| 	push(@out,"\t$name\t");
 | |
| 	$l=length($p1)+1;
 | |
| 	push(@out,$p1.",");
 | |
| 	$ll=3-($l+9)/8;
 | |
| 	$tmp1=sprintf("\t" x $ll);
 | |
| 	push(@out,$tmp1);
 | |
| 
 | |
| 	push(@out,&conv($p2)."\n");
 | |
| 	}
 | |
| 
 | |
| sub out1
 | |
| 	{
 | |
| 	local($name,$p1)=@_;
 | |
| 
 | |
| 	$p1=&conv($p1);
 | |
| 	push(@out,"\t$name\t".$p1."\n");
 | |
| 	}
 | |
| 
 | |
| sub out0
 | |
| 	{
 | |
| 	push(@out,"\t$_[0]\n");
 | |
| 	}
 | |
| 
 | |
| sub main'file
 | |
| 	{
 | |
| 	local($file)=@_;
 | |
| 
 | |
| 	local($tmp)=<<"EOF";
 | |
|  # DEC Alpha assember
 | |
|  # Generated from perl scripts contains in SSLeay
 | |
| 	.file	1 "$file.s"
 | |
| 	.set noat
 | |
| EOF
 | |
| 	push(@out,$tmp);
 | |
| 	}
 | |
| 
 | |
| sub main'function_begin
 | |
| 	{
 | |
| 	local($func)=@_;
 | |
| 
 | |
| print STDERR "$func\n";
 | |
| 	local($tmp)=<<"EOF";
 | |
| 	.text
 | |
| 	.align $align
 | |
| 	.globl $func
 | |
| 	.ent $func
 | |
| ${func}:
 | |
| ${func}..ng:
 | |
| 	.frame \$30,0,\$26,0
 | |
| 	.prologue 0
 | |
| EOF
 | |
| 	push(@out,$tmp);
 | |
| 	$stack=0;
 | |
| 	}
 | |
| 
 | |
| sub main'function_end
 | |
| 	{
 | |
| 	local($func)=@_;
 | |
| 
 | |
| 	local($tmp)=<<"EOF";
 | |
| 	ret	\$31,(\$26),1
 | |
| 	.end $func
 | |
| EOF
 | |
| 	push(@out,$tmp);
 | |
| 	$stack=0;
 | |
| 	%label=();
 | |
| 	}
 | |
| 
 | |
| sub main'function_end_A
 | |
| 	{
 | |
| 	local($func)=@_;
 | |
| 
 | |
| 	local($tmp)=<<"EOF";
 | |
| 	ret	\$31,(\$26),1
 | |
| EOF
 | |
| 	push(@out,$tmp);
 | |
| 	}
 | |
| 
 | |
| sub main'function_end_B
 | |
| 	{
 | |
| 	local($func)=@_;
 | |
| 
 | |
| 	$func=$under.$func;
 | |
| 
 | |
| 	push(@out,"\t.end $func\n");
 | |
| 	$stack=0;
 | |
| 	%label=();
 | |
| 	}
 | |
| 
 | |
| sub main'wparam
 | |
| 	{
 | |
| 	local($num)=@_;
 | |
| 
 | |
| 	if ($num < 6)
 | |
| 		{
 | |
| 		$num=20-$num;
 | |
| 		return("r$num");
 | |
| 		}
 | |
| 	else
 | |
| 		{ return(&main'QWP($stack+$num*8,"sp")); }
 | |
| 	}
 | |
| 
 | |
| sub main'stack_push
 | |
| 	{
 | |
| 	local($num)=@_;
 | |
| 	$stack+=$num*8;
 | |
| 	&main'sub("sp",$num*8,"sp");
 | |
| 	}
 | |
| 
 | |
| sub main'stack_pop
 | |
| 	{
 | |
| 	local($num)=@_;
 | |
| 	$stack-=$num*8;
 | |
| 	&main'add("sp",$num*8,"sp");
 | |
| 	}
 | |
| 
 | |
| sub main'swtmp
 | |
| 	{
 | |
| 	return(&main'QWP(($_[0])*8,"sp"));
 | |
| 	}
 | |
| 
 | |
| # Should use swtmp, which is above sp.  Linix can trash the stack above esp
 | |
| #sub main'wtmp
 | |
| #	{
 | |
| #	local($num)=@_;
 | |
| #
 | |
| #	return(&main'QWP(-($num+1)*4,"esp","",0));
 | |
| #	}
 | |
| 
 | |
| sub main'comment
 | |
| 	{
 | |
| 	foreach (@_)
 | |
| 		{
 | |
| 		if (/^\s*$/)
 | |
| 			{ push(@out,"\n"); }
 | |
| 		else
 | |
| 			{ push(@out,"\t$com_start $_ $com_end\n"); }
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| sub main'label
 | |
| 	{
 | |
| 	if (!defined($label{$_[0]}))
 | |
| 		{
 | |
| 		$label{$_[0]}=$label;
 | |
| 		$label++;
 | |
| 		}
 | |
| 	return('$'.$label{$_[0]});
 | |
| 	}
 | |
| 
 | |
| sub main'set_label
 | |
| 	{
 | |
| 	if (!defined($label{$_[0]}))
 | |
| 		{
 | |
| 		$label{$_[0]}=$label;
 | |
| 		$label++;
 | |
| 		}
 | |
| #	push(@out,".align $align\n") if ($_[1] != 0);
 | |
| 	push(@out,'$'."$label{$_[0]}:\n");
 | |
| 	}
 | |
| 
 | |
| sub main'file_end
 | |
| 	{
 | |
| 	}
 | |
| 
 | |
| sub main'data_word
 | |
| 	{
 | |
| 	push(@out,"\t.long $_[0]\n");
 | |
| 	}
 | |
| 
 | |
| @pool_free=();
 | |
| @pool_taken=();
 | |
| $curr_num=0;
 | |
| $max=0;
 | |
| 
 | |
| sub main'init_pool
 | |
| 	{
 | |
| 	local($args)=@_;
 | |
| 	local($i);
 | |
| 
 | |
| 	@pool_free=();
 | |
| 	for ($i=(14+(6-$args)); $i >= 0; $i--)
 | |
| 		{
 | |
| 		push(@pool_free,"r$i");
 | |
| 		}
 | |
| 	print STDERR "START :register pool:@pool_free\n";
 | |
| 	$curr_num=$max=0;
 | |
| 	}
 | |
| 
 | |
| sub main'fin_pool
 | |
| 	{
 | |
| 	printf STDERR "END %2d:register pool:@pool_free\n",$max;
 | |
| 	}
 | |
| 
 | |
| sub main'GR
 | |
| 	{
 | |
| 	local($r)=@_;
 | |
| 	local($i,@n,$_);
 | |
| 
 | |
| 	foreach (@pool_free)
 | |
| 		{
 | |
| 		if ($r ne $_)
 | |
| 			{ push(@n,$_); }
 | |
| 		else
 | |
| 			{
 | |
| 			$curr_num++;
 | |
| 			$max=$curr_num if ($curr_num > $max);
 | |
| 			}
 | |
| 		}
 | |
| 	@pool_free=@n;
 | |
| print STDERR "GR:@pool_free\n" if $reg_alloc;
 | |
| 	return(@_);
 | |
| 	}
 | |
| 
 | |
| sub main'NR
 | |
| 	{
 | |
| 	local($num)=@_;
 | |
| 	local(@ret);
 | |
| 
 | |
| 	$num=1 if $num == 0;
 | |
| 	($#pool_free >= ($num-1)) || croak "out of registers: want $num, have @pool_free";
 | |
| 	while ($num > 0)
 | |
| 		{
 | |
| 		push(@ret,pop @pool_free);
 | |
| 		$curr_num++;
 | |
| 		$max=$curr_num if ($curr_num > $max);
 | |
| 		$num--
 | |
| 		}
 | |
| 	print STDERR "nr @ret\n" if $n_debug;
 | |
| print STDERR "NR:@pool_free\n" if $reg_alloc;
 | |
| 	return(@ret);
 | |
| 
 | |
| 	}
 | |
| 
 | |
| sub main'FR
 | |
| 	{
 | |
| 	local(@r)=@_;
 | |
| 	local(@a,$v,$w);
 | |
| 
 | |
| 	print STDERR "fr @r\n" if $n_debug;
 | |
| #	cluck "fr @r";
 | |
| 	for $w (@pool_free)
 | |
| 		{
 | |
| 		foreach $v (@r)
 | |
| 			{
 | |
| 			croak "double register free of $v (@pool_free)" if $w eq $v;
 | |
| 			}
 | |
| 		}
 | |
| 	foreach $v (@r)
 | |
| 		{
 | |
| 		croak "bad argument to FR" if ($v !~ /^r\d+$/);
 | |
| 		if ($smear_regs)
 | |
| 			{ unshift(@pool_free,$v); }
 | |
| 		else	{ push(@pool_free,$v); }
 | |
| 		$curr_num--;
 | |
| 		}
 | |
| print STDERR "FR:@pool_free\n" if $reg_alloc;
 | |
| 	}
 | |
| 1;
 | 
