1#!/bin/sh
2#
3# BEGIN LICENSE BLOCK
4# Version: CMPL 1.1
5#
6# The contents of this file are subject to the Cisco-style Mozilla Public
7# License Version 1.1 (the "License"); you may not use this file except
8# in compliance with the License.  You may obtain a copy of the License
9# at www.eclipse-clp.org/license.
10# 
11# Software distributed under the License is distributed on an "AS IS"
12# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
13# the License for the specific language governing rights and limitations
14# under the License. 
15# 
16# The Original Code is  The ECLiPSe Constraint Logic Programming System. 
17# The Initial Developer of the Original Code is  Cisco Systems, Inc. 
18# Portions created by the Initial Developer are
19# Copyright (C) 1992-2006 Cisco Systems, Inc.  All Rights Reserved.
20# 
21# Contributor(s): ___________________________________. 
22# 
23# END LICENSE BLOCK
24#
25# IDENTIFICATION	opt_sun4.sh
26#
27# AUTHOR		Joachim Schimpf
28#
29# DESCRIPTION		A postprocessor to optimize the assembler source
30#			that the SUN-4 C compiler generates from emu.c.
31#			The main purpose is to turn the normal emulator
32#			into a threaded code emulator.
33#
34#			In order to make this postprocessor work,
35#			emu.c must be compiled with
36#
37#				cc [-O[12]] -DTHREADED -DPOSTPRO -S emu.c
38#
39#			-DNO_ESCAPE is not allowed!
40#
41# USAGE			opt_sun4.sh emu.s <infile> <outfile>
42#
43
44trap 'rm -f /tmp/opt?.$$' 0
45
46#
47# Optimizer pass 0 (analysis)
48#
49# finds:
50#	- the label of the switch table
51#
52
53cat > /tmp/opt0.$$ <<\'PASS1a\'
54
55/L.+:/ {
56	thislabel = $1
57	words = 0			# check if a table follows
58	getline
59	while ($0 ~ /^	\.word/) {
60		words++
61		getline
62	}
63	if (words > 200) {		# switch table found
64		optable = thislabel
65	}
66}
67
68END {
69	print optable			# pass table label to pass1
70}
71'PASS1a'
72
73#
74# Optimizer pass 1 (analysis)
75#
76# finds:
77#	- the 2 code labels of the opcode switch
78#	- the register that holds PP
79#
80
81cat > /tmp/opt1.$$ <<\'PASS1b\'
82
83BEGIN {
84	getline
85	optable = $0				# e.g. "L2000118:"
86	table_label = substr($0,1,length($0)-1)
87}
88
89$1 ~ /L.+:/ {
90	line1 = $1
91	getline
92	line2 = $0
93	getline
94	if ($1 ~ /L.+:/) {
95		label1 = line1
96		instr = line2
97		label2 = $1
98	}
99}
100    
101$2 ~ /L.+/ {
102	if (index($2, table_label)) {
103		loop1 = label1
104		slot = instr
105		loop2 = label2
106	}
107}
108
109/^\tld\t.*bip_error_code_.*/ {		# an assignment to pp, remember the register
110	pp = substr($2, length($2)-2, 3)
111}
112
113END {
114	print pp			# pass results to pass2
115	print loop1
116	print slot
117	print loop2
118	print optable
119}
120'PASS1b'
121
122#
123# Optimizer pass 2 (transformation)
124#
125# - replace jumps to the switch labels by threaded code jumps
126# - add the op_addr label to the switch table
127#
128
129cat > /tmp/opt2.$$ <<\'PASS2\'
130
131BEGIN	{
132	getline
133	pp = $0					# e.g. "%i0"
134	getline
135	loop1def = $0
136	loop1 = substr($0,1,length($0)-1)	# e.g. "L504"
137	getline
138	slot = $0				# add or mov instruction
139	getline
140	loop2 = substr($0,1,length($0)-1)	# e.g. "LY224" or "no label"
141	getline
142	optable = $0				# e.g. "L2000118:"
143}
144
145{
146	if ($2 == loop1) {
147	    if ($1 == "b") {
148		getline
149		if ($1 != "nop") {
150		    if ($2 ~ /%o0/ || substr($2,length($2)-2,3) == pp) {
151			print
152			print "\tld\t[" pp "],%o0"
153		    } else {
154			print "\tld\t[" pp "],%o0"
155			print
156		    }
157		} else {
158		    print "\tld\t[" pp "],%o0"
159		}
160		print "\tjmpl\t%o0,%g0"
161		print "\tadd\t" pp ",4," pp
162	    } else {
163		print "\t" $1 "\tLnewloop1"	# works even for .word
164	    }
165	} else if ($2 == loop2) {
166	    if ($1 == "b") {
167		print "\tld\t[" pp "],%o0"
168		print "\tjmpl\t%o0,%g0"
169		print "\tadd\t" pp ",4," pp
170	    } else {
171		if ($1 !~ /,a$/) {
172		    print "OPTIMIZER: anull flag expected in " $0
173		    exit
174		}
175		print "\t" $1 "\tLnewloop2"
176		print "\tld\t[" pp "],%o0"
177	    }
178	    getline		# skip the useless delay slot instruction
179	    if (!index($0, slot)) {
180		print "OPTIMIZER: unexpected instruction " $0
181		exit
182	    }
183	} else if ($1 == loop1def) {
184	    print "Lnewloop1:"
185	    print "\tld\t[" pp "],%o0"
186	    print "Lnewloop2:"
187	    print "\tjmpl\t%o0,%g0"
188	    print "\tadd\t" pp ",4," pp
189	    print
190	} else if ($1 == optable) {
191	    print "_op_addr:"
192	    print
193	} else if ($1 == ".global" && !already_printed) {
194	    already_printed = 1
195	    print "\t.global\t_op_addr"
196	    print
197	} else
198	    print
199}
200'PASS2'
201
202#echo pass0
203awk -f /tmp/opt0.$$ $1 > /tmp/opt9.$$
204#echo pass1
205awk -f /tmp/opt1.$$ /tmp/opt9.$$ $1 > $1.par
206
207#echo pass2
208#awk -f /tmp/opt2.$$ $1.par $1 > $2
209awk -f /tmp/opt2.$$ $1.par $1 | sed -e "s/`head -1 $1.par`/%g6/g" > $2
210
211#
212# The sed script above replaces the register that holds pp by
213# a global sparc register (good choices are g5, g6 or g7).
214#
215# Now create 2 functions to set and return the value of this register.
216#
217
218cat >> $2 <<\'EOF\'
219	.seg	"text"
220	.proc 04
221	.global _get_pp
222_get_pp:
223	retl
224	mov	%g6,%o0
225
226	.proc 04
227	.global _set_pp
228_set_pp:
229	retl
230	mov	%o0,%g6
231	.seg	"data"
232'EOF'
233
234#echo done
235