Implement function-sections for Haskell code, #8405
[ghc.git] / compiler / nativeGen / SPARC / Ppr.hs
1 {-# LANGUAGE CPP #-}
2
3 -----------------------------------------------------------------------------
4 --
5 -- Pretty-printing assembly language
6 --
7 -- (c) The University of Glasgow 1993-2005
8 --
9 -----------------------------------------------------------------------------
10
11 {-# OPTIONS_GHC -fno-warn-orphans #-}
12
13 module SPARC.Ppr (
14 pprNatCmmDecl,
15 pprBasicBlock,
16 pprData,
17 pprInstr,
18 pprFormat,
19 pprImm,
20 pprDataItem
21 )
22
23 where
24
25 #include "HsVersions.h"
26 #include "nativeGen/NCG.h"
27
28 import SPARC.Regs
29 import SPARC.Instr
30 import SPARC.Cond
31 import SPARC.Imm
32 import SPARC.AddrMode
33 import SPARC.Base
34 import Instruction
35 import Reg
36 import Format
37 import PprBase
38
39 import Cmm hiding (topInfoTable)
40 import PprCmm()
41 import CLabel
42 import BlockId
43
44 import Unique ( Uniquable(..), pprUnique )
45 import Outputable
46 import Platform
47 import FastString
48 import Data.Word
49
50 -- -----------------------------------------------------------------------------
51 -- Printing this stuff out
52
53 pprNatCmmDecl :: NatCmmDecl CmmStatics Instr -> SDoc
54 pprNatCmmDecl (CmmData section dats) =
55 pprSectionAlign section $$ pprDatas dats
56
57 pprNatCmmDecl proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
58 case topInfoTable proc of
59 Nothing ->
60 case blocks of
61 [] -> -- special case for split markers:
62 pprLabel lbl
63 blocks -> -- special case for code without info table:
64 pprSectionAlign (Section Text lbl) $$
65 pprLabel lbl $$ -- blocks guaranteed not null, so label needed
66 vcat (map (pprBasicBlock top_info) blocks)
67
68 Just (Statics info_lbl _) ->
69 sdocWithPlatform $ \platform ->
70 (if platformHasSubsectionsViaSymbols platform
71 then pprSectionAlign dspSection $$
72 ppr (mkDeadStripPreventer info_lbl) <> char ':'
73 else empty) $$
74 vcat (map (pprBasicBlock top_info) blocks) $$
75 -- above: Even the first block gets a label, because with branch-chain
76 -- elimination, it might be the target of a goto.
77 (if platformHasSubsectionsViaSymbols platform
78 then
79 -- See Note [Subsections Via Symbols]
80 text "\t.long "
81 <+> ppr info_lbl
82 <+> char '-'
83 <+> ppr (mkDeadStripPreventer info_lbl)
84 else empty)
85
86 dspSection :: Section
87 dspSection = Section Text $
88 panic "subsections-via-symbols doesn't combine with split-sections"
89
90 pprBasicBlock :: BlockEnv CmmStatics -> NatBasicBlock Instr -> SDoc
91 pprBasicBlock info_env (BasicBlock blockid instrs)
92 = maybe_infotable $$
93 pprLabel (mkAsmTempLabel (getUnique blockid)) $$
94 vcat (map pprInstr instrs)
95 where
96 maybe_infotable = case mapLookup blockid info_env of
97 Nothing -> empty
98 Just (Statics info_lbl info) ->
99 pprSectionAlign (Section Text info_lbl) $$
100 vcat (map pprData info) $$
101 pprLabel info_lbl
102
103
104 pprDatas :: CmmStatics -> SDoc
105 pprDatas (Statics lbl dats) = vcat (pprLabel lbl : map pprData dats)
106
107 pprData :: CmmStatic -> SDoc
108 pprData (CmmString str) = pprASCII str
109 pprData (CmmUninitialised bytes) = ptext (sLit ".skip ") <> int bytes
110 pprData (CmmStaticLit lit) = pprDataItem lit
111
112 pprGloblDecl :: CLabel -> SDoc
113 pprGloblDecl lbl
114 | not (externallyVisibleCLabel lbl) = empty
115 | otherwise = ptext (sLit ".global ") <> ppr lbl
116
117 pprTypeAndSizeDecl :: CLabel -> SDoc
118 pprTypeAndSizeDecl lbl
119 = sdocWithPlatform $ \platform ->
120 if platformOS platform == OSLinux && externallyVisibleCLabel lbl
121 then ptext (sLit ".type ") <> ppr lbl <> ptext (sLit ", @object")
122 else empty
123
124 pprLabel :: CLabel -> SDoc
125 pprLabel lbl = pprGloblDecl lbl
126 $$ pprTypeAndSizeDecl lbl
127 $$ (ppr lbl <> char ':')
128
129
130 pprASCII :: [Word8] -> SDoc
131 pprASCII str
132 = vcat (map do1 str) $$ do1 0
133 where
134 do1 :: Word8 -> SDoc
135 do1 w = ptext (sLit "\t.byte\t") <> int (fromIntegral w)
136
137
138 -- -----------------------------------------------------------------------------
139 -- pprInstr: print an 'Instr'
140
141 instance Outputable Instr where
142 ppr instr = pprInstr instr
143
144
145 -- | Pretty print a register.
146 pprReg :: Reg -> SDoc
147 pprReg reg
148 = case reg of
149 RegVirtual vr
150 -> case vr of
151 VirtualRegI u -> text "%vI_" <> pprUnique u
152 VirtualRegHi u -> text "%vHi_" <> pprUnique u
153 VirtualRegF u -> text "%vF_" <> pprUnique u
154 VirtualRegD u -> text "%vD_" <> pprUnique u
155 VirtualRegSSE u -> text "%vSSE_" <> pprUnique u
156
157 RegReal rr
158 -> case rr of
159 RealRegSingle r1
160 -> pprReg_ofRegNo r1
161
162 RealRegPair r1 r2
163 -> text "(" <> pprReg_ofRegNo r1
164 <> text "|" <> pprReg_ofRegNo r2
165 <> text ")"
166
167
168
169 -- | Pretty print a register name, based on this register number.
170 -- The definition has been unfolded so we get a jump-table in the
171 -- object code. This function is called quite a lot when emitting
172 -- the asm file..
173 --
174 pprReg_ofRegNo :: Int -> SDoc
175 pprReg_ofRegNo i
176 = ptext
177 (case i of {
178 0 -> sLit "%g0"; 1 -> sLit "%g1";
179 2 -> sLit "%g2"; 3 -> sLit "%g3";
180 4 -> sLit "%g4"; 5 -> sLit "%g5";
181 6 -> sLit "%g6"; 7 -> sLit "%g7";
182 8 -> sLit "%o0"; 9 -> sLit "%o1";
183 10 -> sLit "%o2"; 11 -> sLit "%o3";
184 12 -> sLit "%o4"; 13 -> sLit "%o5";
185 14 -> sLit "%o6"; 15 -> sLit "%o7";
186 16 -> sLit "%l0"; 17 -> sLit "%l1";
187 18 -> sLit "%l2"; 19 -> sLit "%l3";
188 20 -> sLit "%l4"; 21 -> sLit "%l5";
189 22 -> sLit "%l6"; 23 -> sLit "%l7";
190 24 -> sLit "%i0"; 25 -> sLit "%i1";
191 26 -> sLit "%i2"; 27 -> sLit "%i3";
192 28 -> sLit "%i4"; 29 -> sLit "%i5";
193 30 -> sLit "%i6"; 31 -> sLit "%i7";
194 32 -> sLit "%f0"; 33 -> sLit "%f1";
195 34 -> sLit "%f2"; 35 -> sLit "%f3";
196 36 -> sLit "%f4"; 37 -> sLit "%f5";
197 38 -> sLit "%f6"; 39 -> sLit "%f7";
198 40 -> sLit "%f8"; 41 -> sLit "%f9";
199 42 -> sLit "%f10"; 43 -> sLit "%f11";
200 44 -> sLit "%f12"; 45 -> sLit "%f13";
201 46 -> sLit "%f14"; 47 -> sLit "%f15";
202 48 -> sLit "%f16"; 49 -> sLit "%f17";
203 50 -> sLit "%f18"; 51 -> sLit "%f19";
204 52 -> sLit "%f20"; 53 -> sLit "%f21";
205 54 -> sLit "%f22"; 55 -> sLit "%f23";
206 56 -> sLit "%f24"; 57 -> sLit "%f25";
207 58 -> sLit "%f26"; 59 -> sLit "%f27";
208 60 -> sLit "%f28"; 61 -> sLit "%f29";
209 62 -> sLit "%f30"; 63 -> sLit "%f31";
210 _ -> sLit "very naughty sparc register" })
211
212
213 -- | Pretty print a format for an instruction suffix.
214 pprFormat :: Format -> SDoc
215 pprFormat x
216 = ptext
217 (case x of
218 II8 -> sLit "ub"
219 II16 -> sLit "uh"
220 II32 -> sLit ""
221 II64 -> sLit "d"
222 FF32 -> sLit ""
223 FF64 -> sLit "d"
224 _ -> panic "SPARC.Ppr.pprFormat: no match")
225
226
227 -- | Pretty print a format for an instruction suffix.
228 -- eg LD is 32bit on sparc, but LDD is 64 bit.
229 pprStFormat :: Format -> SDoc
230 pprStFormat x
231 = ptext
232 (case x of
233 II8 -> sLit "b"
234 II16 -> sLit "h"
235 II32 -> sLit ""
236 II64 -> sLit "x"
237 FF32 -> sLit ""
238 FF64 -> sLit "d"
239 _ -> panic "SPARC.Ppr.pprFormat: no match")
240
241
242 -- | Pretty print a condition code.
243 pprCond :: Cond -> SDoc
244 pprCond c
245 = ptext
246 (case c of
247 ALWAYS -> sLit ""
248 NEVER -> sLit "n"
249 GEU -> sLit "geu"
250 LU -> sLit "lu"
251 EQQ -> sLit "e"
252 GTT -> sLit "g"
253 GE -> sLit "ge"
254 GU -> sLit "gu"
255 LTT -> sLit "l"
256 LE -> sLit "le"
257 LEU -> sLit "leu"
258 NE -> sLit "ne"
259 NEG -> sLit "neg"
260 POS -> sLit "pos"
261 VC -> sLit "vc"
262 VS -> sLit "vs")
263
264
265 -- | Pretty print an address mode.
266 pprAddr :: AddrMode -> SDoc
267 pprAddr am
268 = case am of
269 AddrRegReg r1 (RegReal (RealRegSingle 0))
270 -> pprReg r1
271
272 AddrRegReg r1 r2
273 -> hcat [ pprReg r1, char '+', pprReg r2 ]
274
275 AddrRegImm r1 (ImmInt i)
276 | i == 0 -> pprReg r1
277 | not (fits13Bits i) -> largeOffsetError i
278 | otherwise -> hcat [ pprReg r1, pp_sign, int i ]
279 where
280 pp_sign = if i > 0 then char '+' else empty
281
282 AddrRegImm r1 (ImmInteger i)
283 | i == 0 -> pprReg r1
284 | not (fits13Bits i) -> largeOffsetError i
285 | otherwise -> hcat [ pprReg r1, pp_sign, integer i ]
286 where
287 pp_sign = if i > 0 then char '+' else empty
288
289 AddrRegImm r1 imm
290 -> hcat [ pprReg r1, char '+', pprImm imm ]
291
292
293 -- | Pretty print an immediate value.
294 pprImm :: Imm -> SDoc
295 pprImm imm
296 = case imm of
297 ImmInt i -> int i
298 ImmInteger i -> integer i
299 ImmCLbl l -> ppr l
300 ImmIndex l i -> ppr l <> char '+' <> int i
301 ImmLit s -> s
302
303 ImmConstantSum a b
304 -> pprImm a <> char '+' <> pprImm b
305
306 ImmConstantDiff a b
307 -> pprImm a <> char '-' <> lparen <> pprImm b <> rparen
308
309 LO i
310 -> hcat [ text "%lo(", pprImm i, rparen ]
311
312 HI i
313 -> hcat [ text "%hi(", pprImm i, rparen ]
314
315 -- these should have been converted to bytes and placed
316 -- in the data section.
317 ImmFloat _ -> ptext (sLit "naughty float immediate")
318 ImmDouble _ -> ptext (sLit "naughty double immediate")
319
320
321 -- | Pretty print a section \/ segment header.
322 -- On SPARC all the data sections must be at least 8 byte aligned
323 -- incase we store doubles in them.
324 --
325 pprSectionAlign :: Section -> SDoc
326 pprSectionAlign sec@(Section seg _) =
327 sdocWithPlatform $ \platform ->
328 pprSectionHeader platform sec $$
329 ptext (case seg of
330 Text -> sLit ".align 4"
331 Data -> sLit ".align 8"
332 ReadOnlyData -> sLit ".align 8"
333 RelocatableReadOnlyData
334 -> sLit ".align 8"
335 UninitialisedData -> sLit ".align 8"
336 ReadOnlyData16 -> sLit ".align 16"
337 OtherSection _ -> panic "PprMach.pprSectionHeader: unknown section")
338
339 -- | Pretty print a data item.
340 pprDataItem :: CmmLit -> SDoc
341 pprDataItem lit
342 = sdocWithDynFlags $ \dflags ->
343 vcat (ppr_item (cmmTypeFormat $ cmmLitType dflags lit) lit)
344 where
345 imm = litToImm lit
346
347 ppr_item II8 _ = [ptext (sLit "\t.byte\t") <> pprImm imm]
348 ppr_item II32 _ = [ptext (sLit "\t.long\t") <> pprImm imm]
349
350 ppr_item FF32 (CmmFloat r _)
351 = let bs = floatToBytes (fromRational r)
352 in map (\b -> ptext (sLit "\t.byte\t") <> pprImm (ImmInt b)) bs
353
354 ppr_item FF64 (CmmFloat r _)
355 = let bs = doubleToBytes (fromRational r)
356 in map (\b -> ptext (sLit "\t.byte\t") <> pprImm (ImmInt b)) bs
357
358 ppr_item II16 _ = [ptext (sLit "\t.short\t") <> pprImm imm]
359 ppr_item II64 _ = [ptext (sLit "\t.quad\t") <> pprImm imm]
360 ppr_item _ _ = panic "SPARC.Ppr.pprDataItem: no match"
361
362
363 -- | Pretty print an instruction.
364 pprInstr :: Instr -> SDoc
365
366 -- nuke comments.
367 pprInstr (COMMENT _)
368 = empty
369
370 pprInstr (DELTA d)
371 = pprInstr (COMMENT (mkFastString ("\tdelta = " ++ show d)))
372
373 -- Newblocks and LData should have been slurped out before producing the .s file.
374 pprInstr (NEWBLOCK _)
375 = panic "X86.Ppr.pprInstr: NEWBLOCK"
376
377 pprInstr (LDATA _ _)
378 = panic "PprMach.pprInstr: LDATA"
379
380 -- 64 bit FP loads are expanded into individual instructions in CodeGen.Expand
381 pprInstr (LD FF64 _ reg)
382 | RegReal (RealRegSingle{}) <- reg
383 = panic "SPARC.Ppr: not emitting potentially misaligned LD FF64 instr"
384
385 pprInstr (LD format addr reg)
386 = hcat [
387 ptext (sLit "\tld"),
388 pprFormat format,
389 char '\t',
390 lbrack,
391 pprAddr addr,
392 pp_rbracket_comma,
393 pprReg reg
394 ]
395
396 -- 64 bit FP storees are expanded into individual instructions in CodeGen.Expand
397 pprInstr (ST FF64 reg _)
398 | RegReal (RealRegSingle{}) <- reg
399 = panic "SPARC.Ppr: not emitting potentially misaligned ST FF64 instr"
400
401 -- no distinction is made between signed and unsigned bytes on stores for the
402 -- Sparc opcodes (at least I cannot see any, and gas is nagging me --SOF),
403 -- so we call a special-purpose pprFormat for ST..
404 pprInstr (ST format reg addr)
405 = hcat [
406 ptext (sLit "\tst"),
407 pprStFormat format,
408 char '\t',
409 pprReg reg,
410 pp_comma_lbracket,
411 pprAddr addr,
412 rbrack
413 ]
414
415
416 pprInstr (ADD x cc reg1 ri reg2)
417 | not x && not cc && riZero ri
418 = hcat [ ptext (sLit "\tmov\t"), pprReg reg1, comma, pprReg reg2 ]
419
420 | otherwise
421 = pprRegRIReg (if x then sLit "addx" else sLit "add") cc reg1 ri reg2
422
423
424 pprInstr (SUB x cc reg1 ri reg2)
425 | not x && cc && reg2 == g0
426 = hcat [ ptext (sLit "\tcmp\t"), pprReg reg1, comma, pprRI ri ]
427
428 | not x && not cc && riZero ri
429 = hcat [ ptext (sLit "\tmov\t"), pprReg reg1, comma, pprReg reg2 ]
430
431 | otherwise
432 = pprRegRIReg (if x then sLit "subx" else sLit "sub") cc reg1 ri reg2
433
434 pprInstr (AND b reg1 ri reg2) = pprRegRIReg (sLit "and") b reg1 ri reg2
435
436 pprInstr (ANDN b reg1 ri reg2) = pprRegRIReg (sLit "andn") b reg1 ri reg2
437
438 pprInstr (OR b reg1 ri reg2)
439 | not b && reg1 == g0
440 = let doit = hcat [ ptext (sLit "\tmov\t"), pprRI ri, comma, pprReg reg2 ]
441 in case ri of
442 RIReg rrr | rrr == reg2 -> empty
443 _ -> doit
444
445 | otherwise
446 = pprRegRIReg (sLit "or") b reg1 ri reg2
447
448 pprInstr (ORN b reg1 ri reg2) = pprRegRIReg (sLit "orn") b reg1 ri reg2
449
450 pprInstr (XOR b reg1 ri reg2) = pprRegRIReg (sLit "xor") b reg1 ri reg2
451 pprInstr (XNOR b reg1 ri reg2) = pprRegRIReg (sLit "xnor") b reg1 ri reg2
452
453 pprInstr (SLL reg1 ri reg2) = pprRegRIReg (sLit "sll") False reg1 ri reg2
454 pprInstr (SRL reg1 ri reg2) = pprRegRIReg (sLit "srl") False reg1 ri reg2
455 pprInstr (SRA reg1 ri reg2) = pprRegRIReg (sLit "sra") False reg1 ri reg2
456
457 pprInstr (RDY rd) = ptext (sLit "\trd\t%y,") <> pprReg rd
458 pprInstr (WRY reg1 reg2)
459 = ptext (sLit "\twr\t")
460 <> pprReg reg1
461 <> char ','
462 <> pprReg reg2
463 <> char ','
464 <> ptext (sLit "%y")
465
466 pprInstr (SMUL b reg1 ri reg2) = pprRegRIReg (sLit "smul") b reg1 ri reg2
467 pprInstr (UMUL b reg1 ri reg2) = pprRegRIReg (sLit "umul") b reg1 ri reg2
468 pprInstr (SDIV b reg1 ri reg2) = pprRegRIReg (sLit "sdiv") b reg1 ri reg2
469 pprInstr (UDIV b reg1 ri reg2) = pprRegRIReg (sLit "udiv") b reg1 ri reg2
470
471 pprInstr (SETHI imm reg)
472 = hcat [
473 ptext (sLit "\tsethi\t"),
474 pprImm imm,
475 comma,
476 pprReg reg
477 ]
478
479 pprInstr NOP
480 = ptext (sLit "\tnop")
481
482 pprInstr (FABS format reg1 reg2)
483 = pprFormatRegReg (sLit "fabs") format reg1 reg2
484
485 pprInstr (FADD format reg1 reg2 reg3)
486 = pprFormatRegRegReg (sLit "fadd") format reg1 reg2 reg3
487
488 pprInstr (FCMP e format reg1 reg2)
489 = pprFormatRegReg (if e then sLit "fcmpe" else sLit "fcmp")
490 format reg1 reg2
491
492 pprInstr (FDIV format reg1 reg2 reg3)
493 = pprFormatRegRegReg (sLit "fdiv") format reg1 reg2 reg3
494
495 pprInstr (FMOV format reg1 reg2)
496 = pprFormatRegReg (sLit "fmov") format reg1 reg2
497
498 pprInstr (FMUL format reg1 reg2 reg3)
499 = pprFormatRegRegReg (sLit "fmul") format reg1 reg2 reg3
500
501 pprInstr (FNEG format reg1 reg2)
502 = pprFormatRegReg (sLit "fneg") format reg1 reg2
503
504 pprInstr (FSQRT format reg1 reg2)
505 = pprFormatRegReg (sLit "fsqrt") format reg1 reg2
506
507 pprInstr (FSUB format reg1 reg2 reg3)
508 = pprFormatRegRegReg (sLit "fsub") format reg1 reg2 reg3
509
510 pprInstr (FxTOy format1 format2 reg1 reg2)
511 = hcat [
512 ptext (sLit "\tf"),
513 ptext
514 (case format1 of
515 II32 -> sLit "ito"
516 FF32 -> sLit "sto"
517 FF64 -> sLit "dto"
518 _ -> panic "SPARC.Ppr.pprInstr.FxToY: no match"),
519 ptext
520 (case format2 of
521 II32 -> sLit "i\t"
522 II64 -> sLit "x\t"
523 FF32 -> sLit "s\t"
524 FF64 -> sLit "d\t"
525 _ -> panic "SPARC.Ppr.pprInstr.FxToY: no match"),
526 pprReg reg1, comma, pprReg reg2
527 ]
528
529
530 pprInstr (BI cond b blockid)
531 = hcat [
532 ptext (sLit "\tb"), pprCond cond,
533 if b then pp_comma_a else empty,
534 char '\t',
535 ppr (mkAsmTempLabel (getUnique blockid))
536 ]
537
538 pprInstr (BF cond b blockid)
539 = hcat [
540 ptext (sLit "\tfb"), pprCond cond,
541 if b then pp_comma_a else empty,
542 char '\t',
543 ppr (mkAsmTempLabel (getUnique blockid))
544 ]
545
546 pprInstr (JMP addr) = ptext (sLit "\tjmp\t") <> pprAddr addr
547 pprInstr (JMP_TBL op _ _) = pprInstr (JMP op)
548
549 pprInstr (CALL (Left imm) n _)
550 = hcat [ ptext (sLit "\tcall\t"), pprImm imm, comma, int n ]
551
552 pprInstr (CALL (Right reg) n _)
553 = hcat [ ptext (sLit "\tcall\t"), pprReg reg, comma, int n ]
554
555
556 -- | Pretty print a RI
557 pprRI :: RI -> SDoc
558 pprRI (RIReg r) = pprReg r
559 pprRI (RIImm r) = pprImm r
560
561
562 -- | Pretty print a two reg instruction.
563 pprFormatRegReg :: LitString -> Format -> Reg -> Reg -> SDoc
564 pprFormatRegReg name format reg1 reg2
565 = hcat [
566 char '\t',
567 ptext name,
568 (case format of
569 FF32 -> ptext (sLit "s\t")
570 FF64 -> ptext (sLit "d\t")
571 _ -> panic "SPARC.Ppr.pprFormatRegReg: no match"),
572
573 pprReg reg1,
574 comma,
575 pprReg reg2
576 ]
577
578
579 -- | Pretty print a three reg instruction.
580 pprFormatRegRegReg :: LitString -> Format -> Reg -> Reg -> Reg -> SDoc
581 pprFormatRegRegReg name format reg1 reg2 reg3
582 = hcat [
583 char '\t',
584 ptext name,
585 (case format of
586 FF32 -> ptext (sLit "s\t")
587 FF64 -> ptext (sLit "d\t")
588 _ -> panic "SPARC.Ppr.pprFormatRegReg: no match"),
589 pprReg reg1,
590 comma,
591 pprReg reg2,
592 comma,
593 pprReg reg3
594 ]
595
596
597 -- | Pretty print an instruction of two regs and a ri.
598 pprRegRIReg :: LitString -> Bool -> Reg -> RI -> Reg -> SDoc
599 pprRegRIReg name b reg1 ri reg2
600 = hcat [
601 char '\t',
602 ptext name,
603 if b then ptext (sLit "cc\t") else char '\t',
604 pprReg reg1,
605 comma,
606 pprRI ri,
607 comma,
608 pprReg reg2
609 ]
610
611 {-
612 pprRIReg :: LitString -> Bool -> RI -> Reg -> SDoc
613 pprRIReg name b ri reg1
614 = hcat [
615 char '\t',
616 ptext name,
617 if b then ptext (sLit "cc\t") else char '\t',
618 pprRI ri,
619 comma,
620 pprReg reg1
621 ]
622 -}
623
624 {-
625 pp_ld_lbracket :: SDoc
626 pp_ld_lbracket = ptext (sLit "\tld\t[")
627 -}
628
629 pp_rbracket_comma :: SDoc
630 pp_rbracket_comma = text "],"
631
632
633 pp_comma_lbracket :: SDoc
634 pp_comma_lbracket = text ",["
635
636
637 pp_comma_a :: SDoc
638 pp_comma_a = text ",a"
639