File: gen-fn.sml

package info (click to toggle)
mlton 20210117%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 58,464 kB
  • sloc: ansic: 27,682; sh: 4,455; asm: 3,569; lisp: 2,879; makefile: 2,347; perl: 1,169; python: 191; pascal: 68; javascript: 7
file content (308 lines) | stat: -rw-r--r-- 11,816 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
(* gen-fn.sml
 *
 * Generate the interpreter loop.
 *) 

functor GenFn (
    structure T : MLTREE
    structure CCallGen : C_CALL_GEN
      where T = T
  (* general-purpose registers used for passing or returning arguments *)
    val gprs : T.reg list
  (* floating-point registers used for passing or returning arguments *)
    val fprs : T.reg list
  (* possible widths *)
    val gprWidths : T.ty list
    val fprWidths : T.ty list
  (* stack pointer register *)
    val spReg : T.rexp
    val defaultWidth : T.ty
    val callerSaves : T.reg list
    val callerSavesF : T.reg list
  ) :> sig

  (* generate the machine-independent part of the vararg interpreter *)
    val gen : {interpFunPtr : T.rexp, largsReg : T.reg, endOfLargs : T.rexp} -> T.stm list

  end = struct

    structure T = CCallGen.T
    structure Consts = VarargConstants
    structure SA = CCallGen.SA

    datatype loc 
      = REG_LOC of T.reg
      | STK_LOC

    datatype loc_kind = datatype CLocKind.loc_kind

  (* as we go from top to bottom, we become increasingly specific about the destination of the argument. *)
    datatype branch
      = ENTRY of {larg : T.rexp, ks : loc_kind list, widths : T.ty list, narrowings : T.ty list, locs : loc list}
      | KIND of {larg : T.rexp, k : loc_kind, widths : T.ty list, narrowings : T.ty list, locs : loc list}
      | WIDTH of {larg : T.rexp, k : loc_kind, width : T.ty, narrowings : T.ty list, locs : loc list}
      | NARROWING of {larg : T.rexp, k : loc_kind, width : T.ty, narrowing : T.ty, locs : loc list}
      | LOC of {larg : T.rexp, k : loc_kind, width : T.ty, narrowing : T.ty, loc : loc}

    val regToInt = CellsBasis.physicalRegisterNum
    fun locToInt (REG_LOC r) = regToInt r
      | locToInt STK_LOC = 0

  (* labels *)
    local
	val instLabels = ref ([] : (string * Label.label) list)
	fun newLabel s = (case List.find (fn (s', _) => s' = s) (!instLabels)
                of NONE => let
	           val l = Label.label (s^"L") ()
		   in
		       instLabels := (s, l) :: !instLabels;
		       l
		   end
		 | SOME (s, l) => l
               (* end case *))
	fun kindToString GPR = "GPR"
	  | kindToString FPR = "FPR"
	  | kindToString STK = "STK"
	  | kindToString FSTK = "FSTK"
	val c = String.concatWith "."
	val i2s = Int.toString
	fun locToString (REG_LOC r) = "r"^i2s (regToInt r)
	  | locToString STK_LOC = "stk"
	fun instToString (ENTRY {...}) = "entry"
	  | instToString (KIND {k, ...}) = c["kind", kindToString k]
	  | instToString (WIDTH {k, width, ...}) = c["width", kindToString k, i2s width]
	  | instToString (NARROWING {k, width, narrowing, ...}) = 
	        c["narrowing", kindToString k, i2s width, i2s narrowing]
	  | instToString (LOC {k, width, narrowing, loc, ...}) = 
	        c["loc", kindToString k, i2s width, i2s narrowing, locToString loc]
    in
  (* generates labels for instructions *)
    val labelOfInst = newLabel o instToString
    val interpEntryLab = newLabel "interpEntry"
    val interpLab = newLabel "interp"
    val gotoCLab = newLabel "gotoC"
    val errLab = Label.global "vararg_error"
    end (* local *)

    val defTy = defaultWidth
    val mem = T.Region.memory
    val stack = T.Region.stack
    fun lit i = T.LI (T.I.fromInt (defTy, i))
    val lit' = lit o Word32.toInt
    fun gpr r = T.GPR (T.REG (defTy, r))
    fun fpr (ty, f) = T.FPR (T.FREG (ty, f))
    fun concatMap f xs = List.concat (List.map f xs)

  (* displacement from the located argument *)
    fun offLocdArg (ty, larg, off) = T.LOAD(ty, T.ADD(defTy, larg, lit' off), mem)
    fun offLocdArgF (ty, larg, off) = T.FLOAD(ty, T.ADD(defTy, larg, lit' off), mem)

  (* store an integer argument on the stack *)
    fun storeSTK larg ty = 
	    T.STORE(ty, T.ADD (defTy, spReg, offLocdArg(defTy, larg, Consts.locOffB)), 
		    offLocdArg(ty, larg, Consts.argOffB), mem)

  (* store a floating-point argument on the stack *)
    fun storeFSTK larg ty = 
	    T.FSTORE(ty, T.ADD (defTy, spReg, offLocdArg(defTy, larg, Consts.locOffB)), 
		    offLocdArgF(ty, larg, Consts.argOffB), mem)

  (* are the width and narrowing legal for kind of location? *)
    fun widthOK (k, w, narrowing) = let
	    val ws = (case k
		       of (GPR | STK) => gprWidths
			| (FPR | FSTK) => fprWidths)
            in
	       List.exists (fn w' => w = w') ws andalso List.exists (fn w' => narrowing = w') ws
	    end

  (* generate code that places the argument *)
    fun loc {larg, k : CLocKind.loc_kind, width, narrowing, loc} = let
          (* offset into the argument (only nonzero if the argument has an aggregate type) *)
	    val argMembOff = offLocdArg(width, larg, Consts.offsetOffB)
          (* narrow the location if necessary *)
	    fun narrow loc = if width = narrowing then loc
			     else SA.NARROW(loc, width, k)
	    val writeArgInstrs = (
		case (k, loc, widthOK(k, width, narrowing))
		 of (GPR, REG_LOC r, true) => 
		    CCallGen.writeLoc (CCallGen.ARG (offLocdArg(width, larg, Consts.argOffB)))
				      (argMembOff, narrow(SA.REG(width, GPR, r)), [])
		  | (FPR, REG_LOC r, true) =>
		    CCallGen.writeLoc (CCallGen.FARG (offLocdArgF(width, larg, Consts.argOffB)))
				      (argMembOff, narrow(SA.REG(width, FPR, r)), [])
		  | (STK, STK_LOC, true) =>
		    [storeSTK larg width]
		  | (FSTK, STK_LOC, true) =>
		    [storeFSTK larg width]
		  | _ => [T.JMP (T.LABEL errLab, [])]
               (* end case *))
            in
		 (* instructions to write the argument to the location *)
		   writeArgInstrs @
		 (* return to the interpreter loop *)
		   [T.JMP (T.LABEL interpLab, [])]
	    end

    fun genHandlers (i, f, instrs) = let
	    fun genHandler instr = let
		    val lab = labelOfInst (i instr)
		    in
                      List.concat [
	               [T.DEFINE lab],
		       f instr,
		       [T.JMP (T.LABEL errLab, [])]
		    ]    
	           end
            in
	       concatMap genHandler instrs
	    end

  (* generate code to handle an argument narrowing *)
    fun narrowing {larg, k, width, narrowing, locs} = let
	  (* we only use this instruction for generating labels *)
	    fun branch loc = LOC {larg=larg, k=k, width=width, narrowing=narrowing, loc=loc}
	    val locBranches = List.map (labelOfInst o branch) locs
	    fun instr (loc, branch) = if (k = GPR orelse k = FPR)
                    then T.BCC(T.CMP(defTy, T.EQ, 
				     offLocdArg(defTy, larg, Consts.locOffB),
				     lit (locToInt loc)),
			       branch)
                    else T.JMP (T.LABEL branch, [])
            in
	       ListPair.map instr (locs, locBranches)
	    end

  (* generate code to handle an argument width *)
    fun width {larg, k, width, narrowings, locs} = let
	  (* we only use this instruction for generating labels *)
	    fun branch narrowing = NARROWING {larg=larg, k=k, width=width, narrowing=narrowing, locs=locs}
	    val narrowingBranches = List.map (labelOfInst o branch) narrowings
	    fun instr (narrowing, branch) =
		    T.BCC(T.CMP(defTy, T.EQ, 
				offLocdArg(defTy, larg, Consts.narrowingOffB),
				lit narrowing),
			  branch)
            in
	       ListPair.map instr (narrowings, narrowingBranches)
	    end

  (* generate code to handle an argument kind *)
    fun kind {larg, k, widths, narrowings, locs} = let
	    fun branch width = WIDTH {larg=larg, k=k, width=width, narrowings=narrowings, locs=locs}
	    val widthBranches = List.map (labelOfInst o branch) widths
	    fun instr (width, branch) =
		    T.BCC(T.CMP(defTy, T.EQ, 
				offLocdArg(defTy, larg, Consts.widthOffB),
				lit width),
			  branch)
            in
	       ListPair.map instr (widths, widthBranches)
	    end

  (* generate code to handle an argument kind *)
    fun entry {larg, ks, widths, narrowings, locs} = let
	    fun branch k = KIND {larg=larg, k=k, widths=widths, narrowings=narrowings, locs=locs}
	    val kBranches = List.map (labelOfInst o branch) ks
	    fun instr (k, branch) =
		    T.BCC(T.CMP(defTy, T.EQ, 
				offLocdArg(defTy, larg, Consts.kindOffB),
				lit'(Consts.kind k)),
			  branch)
            in
	       ListPair.map instr (ks, kBranches)
	    end

    fun locInstrs {larg, k, width, narrowing, locs=[]} = []
      | locInstrs {larg, k, width, narrowing, locs=loc::locs} =
	    {larg=larg, k=k, width=width, narrowing=narrowing, loc=loc} :: 
	      locInstrs {larg=larg, k=k, width=width, narrowing=narrowing, locs=locs}

    fun widthOK ((STK | GPR), width) = List.exists (fn width' => width' = width) gprWidths
      | widthOK ((FSTK | FPR), width) = List.exists (fn width' => width' = width) fprWidths

    fun narrowingInstrs {larg, k, width, narrowings=[], locs} = []
      | narrowingInstrs {larg, k, width, narrowings=narrowing::narrowings, locs} = let
	    val instrs = narrowingInstrs {larg=larg, k=k, width=width, narrowings=narrowings, locs=locs}
	    in
	      if widthOK(k, narrowing)
	         then {larg=larg, k=k, width=width, narrowing=narrowing, locs=locs} :: instrs
	      else instrs
	    end
	      

    fun widthInstrs {larg, k, widths=[], narrowings, locs} = []
      | widthInstrs {larg, k, widths=width::widths, narrowings, locs} = let
	    val instrs = widthInstrs {larg=larg, k=k, widths=widths, narrowings=narrowings, locs=locs}
	    in
              if widthOK(k, width)
	      then 
		{larg=larg, k=k, width=width, narrowings=narrowings, locs=locs} :: instrs
	      else instrs
            end		

    fun kindInstrs {larg, ks=[], widths, narrowings, locs} = []
      | kindInstrs {larg, ks=k::ks, widths, narrowings, locs} = 
	    {larg=larg, k=k, widths=widths, narrowings=narrowings, locs=locs} :: 
	      kindInstrs {larg=larg, ks=ks, widths=widths, narrowings=narrowings, locs=locs}

    structure IS = IntBinarySet
    fun mkUnique ints = IS.listItems(IS.addList(IS.empty, ints))

    fun entryInstr larg = let
	    val ks = [GPR, FPR, STK, FSTK]
	    val widths = mkUnique (gprWidths@fprWidths)
	    val narrowings = widths
	    val locs = STK_LOC :: List.map REG_LOC gprs @ List.map REG_LOC fprs
            in
	       {larg=larg, ks=ks, widths=widths, narrowings=narrowings, locs=locs}
	    end

  (* all possible combinations of instructions *)
    fun allInstrs larg = let
	    val entryInstr = entryInstr larg
	    val kindInstrs = kindInstrs entryInstr
	    val widthInstrs = concatMap widthInstrs kindInstrs
	    val narrowingInstrs = concatMap narrowingInstrs widthInstrs
	    val locInstrs = concatMap locInstrs narrowingInstrs 
            in
	         (entryInstr, kindInstrs, widthInstrs, narrowingInstrs, locInstrs)
	    end

  (* call the varargs C function *)
    fun genCallC interpFunPtr = let
	   val defs = List.map gpr callerSaves @ List.map (fn r => fpr(64, r)) callerSavesF
	   val uses = List.map gpr gprs @ List.map (fn r => fpr(64, r)) fprs
	   in
	      [
	       T.DEFINE gotoCLab,
	       T.CALL {funct=interpFunPtr, targets=[], defs=defs, uses=uses, region=mem, pops=0}
	      ]
	   end

  (* interpreter for varlargs *)
    fun genInterp (largs, largsReg, endOfLargs) = [
            T.DEFINE interpLab,
	  (* loop through the largs *)
	    T.MV (defTy, largsReg, T.ADD (defTy, largs, lit' Consts.locdArgSzB)),
	    T.DEFINE interpEntryLab,
	    T.BCC (T.CMP(defTy, T.GE, largs, endOfLargs), gotoCLab)
          ]

    fun gen {interpFunPtr, largsReg, endOfLargs} = let           
	    val largs = T.REG (defTy, largsReg)
	    val (entryInstr, kindInstrs, widthInstrs, narrowingInstrs, locInstrs) = allInstrs largs
            in
	      List.concat [
	         [T.JMP (T.LABEL interpEntryLab, [])],
	         genInterp(largs, largsReg, endOfLargs),
		 genHandlers(ENTRY, entry, [entryInstr]),
		 genHandlers(KIND, kind, kindInstrs), 
		 genHandlers(WIDTH, width, widthInstrs), 
		 genHandlers(NARROWING, narrowing, narrowingInstrs),
		 genHandlers(LOC, loc, locInstrs), 
		 genCallC interpFunPtr
	      ]
	    end

  end (* GenFn *)