source: webkit/trunk/Source/JavaScriptCore/offlineasm/ast.rb

Last change on this file was 281541, checked in by [email protected], 4 years ago

[Re-landing] Add some offlineasm enhancements.
https://bugs.webkit.org/show_bug.cgi?id=229332
rdar://82163923

Reviewed by Keith Miller.

  1. Enhance "include" offlineasm Instruction to always attempt to include an asm file from <build-products>/usr/local/include/WebKitAdditions/ first. If the specified file is not available there, then it will attempt to include the file from the same directory as the current source file (which in practice, means Source/JavaScriptCore/llint/).
  1. Enhance "include" offlineasm Instruction to allow an optional file to be included if it exists. For example, the following offlineasm code:

include? LowLevelInterpreterAdditions

... will attempt to include a file LowLevelInterpreterAdditions.asm. If the
file does not exist, this will be a no-op. Note: the "?" after the "include"
means the include is optional.

  1. Enhanced "emit" offlineasm Instruction to be able to take more than one operand.

"emit" used to just copy the string operand that follows into the generated
LLIntAssembly.h. Now, "emit" can take multiple comma separated operands, and
will concatenate all the operands.

Additionally, "emit" can now take a LocalLabelReference as an operand. For
example, this offline asm code:

emit "b ", .done
...

.done:

... will generate this inline asm code in LLIntAssembly.h:

"b " LOCAL_LABEL_STRING(_offlineasm_someLabel_done) "\n"

This makes it easier to emit branches to local labels.

  1. Also fixed LLInt code alignment for ARM_THUMB2 and ARM64.

Previously, it was aligned using ".align 4" which means aligned on a 4
instruction boundary. Note: the interpretation of .align varies for different
target CPU architectures.

Now, we do the alignment using ".balign 4" which means align on a 4 byte
boundary. This is the intended alignment because ARM64 instruction size is
4 bytes, and ARM_THUMB2 instruction size is either 2 bytes or 4 bytes.
Using .align before was potentially wasting some code space.

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter.cpp:
  • offlineasm/ast.rb:
  • offlineasm/parser.rb:
File size: 27.4 KB
Line 
1# Copyright (C) 2011-2020 Apple Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions
5# are met:
6# 1. Redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer.
8# 2. Redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution.
11#
12# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
13# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
16# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
22# THE POSSIBILITY OF SUCH DAMAGE.
23
24require "config"
25
26#
27# Base utility types for the AST.
28#
29
30# Valid methods for Node:
31#
32# node.children -> Returns an array of immediate children.
33#
34# node.descendants -> Returns an array of all strict descendants (children
35# and children of children, transitively).
36#
37# node.flatten -> Returns an array containing the strict descendants and
38# the node itself.
39#
40# node.filter(type) -> Returns an array containing those elements in
41# node.flatten that are of the given type (is_a? type returns true).
42#
43# node.mapChildren{|v| ...} -> Returns a new node with all children
44# replaced according to the given block.
45#
46# Examples:
47#
48# node.filter(Setting).uniq -> Returns all of the settings that the AST's
49# IfThenElse blocks depend on.
50#
51# node.filter(StructOffset).uniq -> Returns all of the structure offsets
52# that the AST depends on.
53
54class Node
55 attr_reader :codeOrigin
56
57 def initialize(codeOrigin)
58 @codeOrigin = codeOrigin
59 end
60
61 def codeOriginString
62 @codeOrigin.to_s
63 end
64
65 def descendants
66 children.collect{|v| v.flatten}.flatten
67 end
68
69 def flatten
70 [self] + descendants
71 end
72
73 def filter(type)
74 flatten.select{|v| v.is_a? type}
75 end
76end
77
78class NoChildren < Node
79 def initialize(codeOrigin)
80 super(codeOrigin)
81 end
82
83 def children
84 []
85 end
86
87 def mapChildren
88 self
89 end
90end
91
92class StructOffsetKey
93 attr_reader :struct, :field
94
95 def initialize(struct, field)
96 @struct = struct
97 @field = field
98 end
99
100 def hash
101 @struct.hash + @field.hash * 3
102 end
103
104 def eql?(other)
105 @struct == other.struct and @field == other.field
106 end
107end
108
109#
110# AST nodes.
111#
112
113class StructOffset < NoChildren
114 attr_reader :struct, :field
115
116 def initialize(codeOrigin, struct, field)
117 super(codeOrigin)
118 @struct = struct
119 @field = field
120 end
121
122 @@mapping = {}
123
124 def self.forField(codeOrigin, struct, field)
125 key = StructOffsetKey.new(struct, field)
126
127 unless @@mapping[key]
128 @@mapping[key] = StructOffset.new(codeOrigin, struct, field)
129 end
130 @@mapping[key]
131 end
132
133 def dump
134 "#{struct}::#{field}"
135 end
136
137 def <=>(other)
138 if @struct != other.struct
139 return @struct <=> other.struct
140 end
141 @field <=> other.field
142 end
143
144 def address?
145 false
146 end
147
148 def label?
149 false
150 end
151
152 def immediate?
153 true
154 end
155
156 def register?
157 false
158 end
159end
160
161class Sizeof < NoChildren
162 attr_reader :struct
163
164 def initialize(codeOrigin, struct)
165 super(codeOrigin)
166 @struct = struct
167 end
168
169 @@mapping = {}
170
171 def self.forName(codeOrigin, struct)
172 unless @@mapping[struct]
173 @@mapping[struct] = Sizeof.new(codeOrigin, struct)
174 end
175 @@mapping[struct]
176 end
177
178 def dump
179 "sizeof #{@struct}"
180 end
181
182 def <=>(other)
183 @struct <=> other.struct
184 end
185
186 def address?
187 false
188 end
189
190 def label?
191 false
192 end
193
194 def immediate?
195 true
196 end
197
198 def register?
199 false
200 end
201end
202
203class Immediate < NoChildren
204 attr_reader :value
205
206 def initialize(codeOrigin, value)
207 super(codeOrigin)
208 @value = value
209 raise "Bad immediate value #{value.inspect} at #{codeOriginString}" unless value.is_a? Integer
210 end
211
212 def dump
213 "#{value}"
214 end
215
216 def ==(other)
217 other.is_a? Immediate and other.value == @value
218 end
219
220 def address?
221 false
222 end
223
224 def label?
225 false
226 end
227
228 def immediate?
229 true
230 end
231
232 def immediateOperand?
233 true
234 end
235
236 def register?
237 false
238 end
239end
240
241class AddImmediates < Node
242 attr_reader :left, :right
243
244 def initialize(codeOrigin, left, right)
245 super(codeOrigin)
246 @left = left
247 @right = right
248 end
249
250 def children
251 [@left, @right]
252 end
253
254 def mapChildren
255 AddImmediates.new(codeOrigin, (yield @left), (yield @right))
256 end
257
258 def dump
259 "(#{left.dump} + #{right.dump})"
260 end
261
262 def value
263 "#{left.value} + #{right.value}"
264 end
265
266 def address?
267 false
268 end
269
270 def label?
271 false
272 end
273
274 def immediate?
275 true
276 end
277
278 def immediateOperand?
279 true
280 end
281
282 def register?
283 false
284 end
285end
286
287class SubImmediates < Node
288 attr_reader :left, :right
289
290 def initialize(codeOrigin, left, right)
291 super(codeOrigin)
292 @left = left
293 @right = right
294 end
295
296 def children
297 [@left, @right]
298 end
299
300 def mapChildren
301 SubImmediates.new(codeOrigin, (yield @left), (yield @right))
302 end
303
304 def dump
305 "(#{left.dump} - #{right.dump})"
306 end
307
308 def value
309 "#{left.value} - #{right.value}"
310 end
311
312 def address?
313 false
314 end
315
316 def label?
317 false
318 end
319
320 def immediate?
321 true
322 end
323
324 def immediateOperand?
325 true
326 end
327
328 def register?
329 false
330 end
331end
332
333class MulImmediates < Node
334 attr_reader :left, :right
335
336 def initialize(codeOrigin, left, right)
337 super(codeOrigin)
338 @left = left
339 @right = right
340 end
341
342 def children
343 [@left, @right]
344 end
345
346 def mapChildren
347 MulImmediates.new(codeOrigin, (yield @left), (yield @right))
348 end
349
350 def dump
351 "(#{left.dump} * #{right.dump})"
352 end
353
354 def address?
355 false
356 end
357
358 def label?
359 false
360 end
361
362 def immediate?
363 true
364 end
365
366 def immediateOperand?
367 false
368 end
369
370 def register?
371 false
372 end
373end
374
375class NegImmediate < Node
376 attr_reader :child
377
378 def initialize(codeOrigin, child)
379 super(codeOrigin)
380 @child = child
381 end
382
383 def children
384 [@child]
385 end
386
387 def mapChildren
388 NegImmediate.new(codeOrigin, (yield @child))
389 end
390
391 def dump
392 "(-#{@child.dump})"
393 end
394
395 def address?
396 false
397 end
398
399 def label?
400 false
401 end
402
403 def immediate?
404 true
405 end
406
407 def immediateOperand?
408 false
409 end
410
411 def register?
412 false
413 end
414end
415
416class OrImmediates < Node
417 attr_reader :left, :right
418
419 def initialize(codeOrigin, left, right)
420 super(codeOrigin)
421 @left = left
422 @right = right
423 end
424
425 def children
426 [@left, @right]
427 end
428
429 def mapChildren
430 OrImmediates.new(codeOrigin, (yield @left), (yield @right))
431 end
432
433 def dump
434 "(#{left.dump} | #{right.dump})"
435 end
436
437 def address?
438 false
439 end
440
441 def label?
442 false
443 end
444
445 def immediate?
446 true
447 end
448
449 def immediateOperand?
450 false
451 end
452
453 def register?
454 false
455 end
456end
457
458class AndImmediates < Node
459 attr_reader :left, :right
460
461 def initialize(codeOrigin, left, right)
462 super(codeOrigin)
463 @left = left
464 @right = right
465 end
466
467 def children
468 [@left, @right]
469 end
470
471 def mapChildren
472 AndImmediates.new(codeOrigin, (yield @left), (yield @right))
473 end
474
475 def dump
476 "(#{left.dump} & #{right.dump})"
477 end
478
479 def address?
480 false
481 end
482
483 def label?
484 false
485 end
486
487 def immediate?
488 true
489 end
490
491 def immediateOperand?
492 false
493 end
494
495 def register?
496 false
497 end
498end
499
500class XorImmediates < Node
501 attr_reader :left, :right
502
503 def initialize(codeOrigin, left, right)
504 super(codeOrigin)
505 @left = left
506 @right = right
507 end
508
509 def children
510 [@left, @right]
511 end
512
513 def mapChildren
514 XorImmediates.new(codeOrigin, (yield @left), (yield @right))
515 end
516
517 def dump
518 "(#{left.dump} ^ #{right.dump})"
519 end
520
521 def address?
522 false
523 end
524
525 def label?
526 false
527 end
528
529 def immediate?
530 true
531 end
532
533 def immediateOperand?
534 false
535 end
536
537 def register?
538 false
539 end
540end
541
542class BitnotImmediate < Node
543 attr_reader :child
544
545 def initialize(codeOrigin, child)
546 super(codeOrigin)
547 @child = child
548 end
549
550 def children
551 [@child]
552 end
553
554 def mapChildren
555 BitnotImmediate.new(codeOrigin, (yield @child))
556 end
557
558 def dump
559 "(~#{@child.dump})"
560 end
561
562 def address?
563 false
564 end
565
566 def label?
567 false
568 end
569
570 def immediate?
571 true
572 end
573
574 def immediateOperand?
575 false
576 end
577
578 def register?
579 false
580 end
581end
582
583class StringLiteral < NoChildren
584 attr_reader :value
585
586 def initialize(codeOrigin, value)
587 super(codeOrigin)
588 @value = value[1..-2]
589 raise "Bad string literal #{value.inspect} at #{codeOriginString}" unless value.is_a? String
590 end
591
592 def dump
593 "#{value}"
594 end
595
596 def ==(other)
597 other.is_a? StringLiteral and other.value == @value
598 end
599
600 def address?
601 false
602 end
603
604 def label?
605 false
606 end
607
608 def immediate?
609 false
610 end
611
612 def immediateOperand?
613 false
614 end
615
616 def register?
617 false
618 end
619end
620
621class RegisterID < NoChildren
622 attr_reader :name
623
624 def initialize(codeOrigin, name)
625 super(codeOrigin)
626 @name = name
627 end
628
629 @@mapping = {}
630
631 def self.forName(codeOrigin, name)
632 unless @@mapping[name]
633 @@mapping[name] = RegisterID.new(codeOrigin, name)
634 end
635 @@mapping[name]
636 end
637
638 def dump
639 name
640 end
641
642 def address?
643 false
644 end
645
646 def label?
647 false
648 end
649
650 def immediate?
651 false
652 end
653
654 def register?
655 true
656 end
657end
658
659class FPRegisterID < NoChildren
660 attr_reader :name
661
662 def initialize(codeOrigin, name)
663 super(codeOrigin)
664 @name = name
665 end
666
667 @@mapping = {}
668
669 def self.forName(codeOrigin, name)
670 unless @@mapping[name]
671 @@mapping[name] = FPRegisterID.new(codeOrigin, name)
672 end
673 @@mapping[name]
674 end
675
676 def dump
677 name
678 end
679
680 def address?
681 false
682 end
683
684 def label?
685 false
686 end
687
688 def immediate?
689 false
690 end
691
692 def immediateOperand?
693 false
694 end
695
696 def register?
697 true
698 end
699end
700
701class SpecialRegister < NoChildren
702 attr_reader :name
703
704 def initialize(name)
705 super(codeOrigin)
706 @name = name
707 end
708
709 def address?
710 false
711 end
712
713 def label?
714 false
715 end
716
717 def immediate?
718 false
719 end
720
721 def immediateOperand?
722 false
723 end
724
725 def register?
726 true
727 end
728end
729
730class Variable < NoChildren
731 attr_reader :name
732
733 def initialize(codeOrigin, name, originalName = nil)
734 super(codeOrigin)
735 @name = name
736 @originalName = originalName
737 end
738
739 @@mapping = {}
740
741 def self.forName(codeOrigin, name, originalName = nil)
742 unless @@mapping[name]
743 @@mapping[name] = Variable.new(codeOrigin, name, originalName)
744 end
745 @@mapping[name]
746 end
747
748 def originalName
749 @originalName || name
750 end
751
752 def dump
753 originalName
754 end
755
756 def inspect
757 "<variable #{originalName} at #{codeOriginString}>"
758 end
759end
760
761class Address < Node
762 attr_reader :base, :offset
763
764 def initialize(codeOrigin, base, offset)
765 super(codeOrigin)
766 @base = base
767 @offset = offset
768 raise "Bad base for address #{base.inspect} at #{codeOriginString}" unless base.is_a? Variable or base.register?
769 raise "Bad offset for address #{offset.inspect} at #{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
770 end
771
772 def withOffset(extraOffset)
773 Address.new(codeOrigin, @base, Immediate.new(codeOrigin, @offset.value + extraOffset))
774 end
775
776 def children
777 [@base, @offset]
778 end
779
780 def mapChildren
781 Address.new(codeOrigin, (yield @base), (yield @offset))
782 end
783
784 def dump
785 "#{offset.dump}[#{base.dump}]"
786 end
787
788 def address?
789 true
790 end
791
792 def label?
793 false
794 end
795
796 def immediate?
797 false
798 end
799
800 def immediateOperand?
801 true
802 end
803
804 def register?
805 false
806 end
807end
808
809class BaseIndex < Node
810 attr_reader :base, :index, :scale, :offset
811
812 def initialize(codeOrigin, base, index, scale, offset)
813 super(codeOrigin)
814 @base = base
815 @index = index
816 @scale = scale
817 @offset = offset
818 end
819
820 def scaleValue
821 raise unless [1, 2, 4, 8].member? scale.value
822 scale.value
823 end
824
825 def scaleShift
826 case scaleValue
827 when 1
828 0
829 when 2
830 1
831 when 4
832 2
833 when 8
834 3
835 else
836 raise "Bad scale: #{scale.value} at #{codeOriginString}"
837 end
838 end
839
840 def withOffset(extraOffset)
841 BaseIndex.new(codeOrigin, @base, @index, @scale, Immediate.new(codeOrigin, @offset.value + extraOffset))
842 end
843
844 def children
845 [@base, @index, @offset]
846 end
847
848 def mapChildren
849 BaseIndex.new(codeOrigin, (yield @base), (yield @index), (yield @scale), (yield @offset))
850 end
851
852 def dump
853 "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale.value}]"
854 end
855
856 def address?
857 true
858 end
859
860 def label?
861 false
862 end
863
864 def immediate?
865 false
866 end
867
868 def immediateOperand?
869 false
870 end
871
872 def register?
873 false
874 end
875end
876
877class AbsoluteAddress < NoChildren
878 attr_reader :address
879
880 def initialize(codeOrigin, address)
881 super(codeOrigin)
882 @address = address
883 end
884
885 def withOffset(extraOffset)
886 AbsoluteAddress.new(codeOrigin, Immediate.new(codeOrigin, @address.value + extraOffset))
887 end
888
889 def dump
890 "#{address.dump}[]"
891 end
892
893 def address?
894 true
895 end
896
897 def label?
898 false
899 end
900
901 def immediate?
902 false
903 end
904
905 def immediateOperand?
906 true
907 end
908
909 def register?
910 false
911 end
912end
913
914class Instruction < Node
915 attr_reader :opcode, :operands, :annotation
916
917 def initialize(codeOrigin, opcode, operands, annotation=nil)
918 super(codeOrigin)
919 @opcode = opcode
920 @operands = operands
921 @annotation = annotation
922 end
923
924 def cloneWithNewOperands(newOperands)
925 Instruction.new(self.codeOrigin, self.opcode, newOperands, self.annotation)
926 end
927
928 def children
929 operands
930 end
931
932 def mapChildren(&proc)
933 Instruction.new(codeOrigin, @opcode, @operands.map(&proc), @annotation)
934 end
935
936 def dump
937 "\t" + opcode.to_s + " " + operands.collect{|v| v.dump}.join(", ")
938 end
939
940 def lowerDefault
941 case opcode
942 when "localAnnotation"
943 $asm.putLocalAnnotation
944 when "globalAnnotation"
945 $asm.putGlobalAnnotation
946 when "emit"
947 str = "";
948 for operand in operands do
949 if (operand.is_a? LocalLabelReference)
950 str += operand.asmLabel
951 else
952 str += "#{operand.dump}"
953 end
954 end
955 $asm.puts "#{str}"
956 when "tagCodePtr", "tagReturnAddress", "untagReturnAddress", "removeCodePtrTag", "untagArrayPtr", "removeArrayPtrTag"
957 else
958 raise "Unhandled opcode #{opcode} at #{codeOriginString}"
959 end
960 end
961
962 def prepareToLower(backendName)
963 if respond_to?("recordMetaData#{backendName}")
964 send("recordMetaData#{backendName}")
965 else
966 recordMetaDataDefault
967 end
968 end
969
970 def recordMetaDataDefault
971 $asm.codeOrigin codeOriginString if $enableCodeOriginComments
972 $asm.annotation annotation if $enableInstrAnnotations
973 $asm.debugAnnotation codeOrigin.debugDirective if $enableDebugAnnotations
974 end
975end
976
977class Error < NoChildren
978 def initialize(codeOrigin)
979 super(codeOrigin)
980 end
981
982 def dump
983 "\terror"
984 end
985end
986
987class ConstExpr < NoChildren
988 attr_reader :value
989
990 def initialize(codeOrigin, value)
991 super(codeOrigin)
992 @value = value
993 end
994
995 @@mapping = {}
996
997 def self.forName(codeOrigin, text)
998 unless @@mapping[text]
999 @@mapping[text] = ConstExpr.new(codeOrigin, text)
1000 end
1001 @@mapping[text]
1002 end
1003
1004 def dump
1005 "constexpr (#{@value.dump})"
1006 end
1007
1008 def <=>(other)
1009 @value <=> other.value
1010 end
1011
1012 def immediate?
1013 true
1014 end
1015end
1016
1017class ConstDecl < Node
1018 attr_reader :variable, :value
1019
1020 def initialize(codeOrigin, variable, value)
1021 super(codeOrigin)
1022 @variable = variable
1023 @value = value
1024 end
1025
1026 def children
1027 [@variable, @value]
1028 end
1029
1030 def mapChildren
1031 ConstDecl.new(codeOrigin, (yield @variable), (yield @value))
1032 end
1033
1034 def dump
1035 "const #{@variable.dump} = #{@value.dump}"
1036 end
1037end
1038
1039$labelMapping = {}
1040$referencedExternLabels = Array.new
1041
1042class Label < NoChildren
1043 def initialize(codeOrigin, name, definedInFile = false)
1044 super(codeOrigin)
1045 @name = name
1046 @definedInFile = definedInFile
1047 @extern = true
1048 @global = false
1049 end
1050
1051 def self.forName(codeOrigin, name, definedInFile = false)
1052 if $labelMapping[name]
1053 raise "Label name collision: #{name}" unless $labelMapping[name].is_a? Label
1054 else
1055 $labelMapping[name] = Label.new(codeOrigin, name, definedInFile)
1056 end
1057 if definedInFile
1058 $labelMapping[name].clearExtern()
1059 end
1060 $labelMapping[name]
1061 end
1062
1063 def self.setAsGlobal(codeOrigin, name)
1064 if $labelMapping[name]
1065 label = $labelMapping[name]
1066 raise "Label: #{name} declared global multiple times" unless not label.global?
1067 label.setGlobal()
1068 else
1069 newLabel = Label.new(codeOrigin, name)
1070 newLabel.setGlobal()
1071 $labelMapping[name] = newLabel
1072 end
1073 end
1074
1075 def self.resetReferenced
1076 $referencedExternLabels = Array.new
1077 end
1078
1079 def self.forReferencedExtern()
1080 $referencedExternLabels.each {
1081 | label |
1082 yield "#{label.name}"
1083 }
1084 end
1085
1086 def clearExtern
1087 @extern = false
1088 end
1089
1090 def extern?
1091 @extern
1092 end
1093
1094 def setGlobal
1095 @global = true
1096 end
1097
1098 def global?
1099 @global
1100 end
1101
1102 def name
1103 @name
1104 end
1105
1106 def dump
1107 "#{name}:"
1108 end
1109end
1110
1111class LocalLabel < NoChildren
1112 attr_reader :name
1113
1114 def initialize(codeOrigin, name)
1115 super(codeOrigin)
1116 @name = name
1117 end
1118
1119 @@uniqueNameCounter = 0
1120
1121 def self.forName(codeOrigin, name)
1122 if $labelMapping[name]
1123 raise "Label name collision: #{name}" unless $labelMapping[name].is_a? LocalLabel
1124 else
1125 $labelMapping[name] = LocalLabel.new(codeOrigin, name)
1126 end
1127 $labelMapping[name]
1128 end
1129
1130 def self.unique(comment)
1131 newName = "_#{comment}"
1132 if $emitWinAsm and newName.length > 90
1133 newName = newName[0...45] + "___" + newName[-45..-1]
1134 end
1135 if $labelMapping[newName]
1136 while $labelMapping[newName = "_#{@@uniqueNameCounter}_#{comment}"]
1137 @@uniqueNameCounter += 1
1138 end
1139 end
1140 forName(nil, newName)
1141 end
1142
1143 def cleanName
1144 if name =~ /^\./
1145 "_" + name[1..-1]
1146 else
1147 name
1148 end
1149 end
1150
1151 def dump
1152 "#{name}:"
1153 end
1154end
1155
1156class LabelReference < Node
1157 attr_reader :label
1158 attr_accessor :offset
1159
1160 def initialize(codeOrigin, label)
1161 super(codeOrigin)
1162 @label = label
1163 @offset = 0
1164 end
1165
1166 def plusOffset(additionalOffset)
1167 result = LabelReference.new(codeOrigin, label)
1168 result.offset = @offset + additionalOffset
1169 result
1170 end
1171
1172 def children
1173 [@label]
1174 end
1175
1176 def mapChildren
1177 result = LabelReference.new(codeOrigin, (yield @label))
1178 result.offset = @offset
1179 result
1180 end
1181
1182 def name
1183 label.name
1184 end
1185
1186 def extern?
1187 $labelMapping[name].is_a? Label and $labelMapping[name].extern?
1188 end
1189
1190 def used
1191 if !$referencedExternLabels.include?(@label) and extern?
1192 $referencedExternLabels.push(@label)
1193 end
1194 end
1195
1196 def dump
1197 label.name
1198 end
1199
1200 def value
1201 asmLabel()
1202 end
1203
1204 def address?
1205 false
1206 end
1207
1208 def label?
1209 true
1210 end
1211
1212 def immediate?
1213 false
1214 end
1215
1216 def immediateOperand?
1217 true
1218 end
1219end
1220
1221class LocalLabelReference < NoChildren
1222 attr_reader :label
1223
1224 def initialize(codeOrigin, label)
1225 super(codeOrigin)
1226 @label = label
1227 end
1228
1229 def children
1230 [@label]
1231 end
1232
1233 def mapChildren
1234 LocalLabelReference.new(codeOrigin, (yield @label))
1235 end
1236
1237 def name
1238 label.name
1239 end
1240
1241 def dump
1242 label.name
1243 end
1244
1245 def value
1246 asmLabel()
1247 end
1248
1249 def address?
1250 false
1251 end
1252
1253 def label?
1254 true
1255 end
1256
1257 def immediate?
1258 false
1259 end
1260
1261 def immediateOperand?
1262 true
1263 end
1264end
1265
1266class Sequence < Node
1267 attr_reader :list
1268
1269 def initialize(codeOrigin, list)
1270 super(codeOrigin)
1271 @list = list
1272 end
1273
1274 def children
1275 list
1276 end
1277
1278 def mapChildren(&proc)
1279 Sequence.new(codeOrigin, @list.map(&proc))
1280 end
1281
1282 def dump
1283 list.collect{|v| v.dump}.join("\n")
1284 end
1285end
1286
1287class True < NoChildren
1288 def initialize
1289 super(nil)
1290 end
1291
1292 @@instance = True.new
1293
1294 def self.instance
1295 @@instance
1296 end
1297
1298 def value
1299 true
1300 end
1301
1302 def dump
1303 "true"
1304 end
1305end
1306
1307class False < NoChildren
1308 def initialize
1309 super(nil)
1310 end
1311
1312 @@instance = False.new
1313
1314 def self.instance
1315 @@instance
1316 end
1317
1318 def value
1319 false
1320 end
1321
1322 def dump
1323 "false"
1324 end
1325end
1326
1327class TrueClass
1328 def asNode
1329 True.instance
1330 end
1331end
1332
1333class FalseClass
1334 def asNode
1335 False.instance
1336 end
1337end
1338
1339class Setting < NoChildren
1340 attr_reader :name
1341
1342 def initialize(codeOrigin, name)
1343 super(codeOrigin)
1344 @name = name
1345 end
1346
1347 @@mapping = {}
1348
1349 def self.forName(codeOrigin, name)
1350 unless @@mapping[name]
1351 @@mapping[name] = Setting.new(codeOrigin, name)
1352 end
1353 @@mapping[name]
1354 end
1355
1356 def dump
1357 name
1358 end
1359end
1360
1361class And < Node
1362 attr_reader :left, :right
1363
1364 def initialize(codeOrigin, left, right)
1365 super(codeOrigin)
1366 @left = left
1367 @right = right
1368 end
1369
1370 def children
1371 [@left, @right]
1372 end
1373
1374 def mapChildren
1375 And.new(codeOrigin, (yield @left), (yield @right))
1376 end
1377
1378 def dump
1379 "(#{left.dump} and #{right.dump})"
1380 end
1381end
1382
1383class Or < Node
1384 attr_reader :left, :right
1385
1386 def initialize(codeOrigin, left, right)
1387 super(codeOrigin)
1388 @left = left
1389 @right = right
1390 end
1391
1392 def children
1393 [@left, @right]
1394 end
1395
1396 def mapChildren
1397 Or.new(codeOrigin, (yield @left), (yield @right))
1398 end
1399
1400 def dump
1401 "(#{left.dump} or #{right.dump})"
1402 end
1403end
1404
1405class Not < Node
1406 attr_reader :child
1407
1408 def initialize(codeOrigin, child)
1409 super(codeOrigin)
1410 @child = child
1411 end
1412
1413 def children
1414 [@child]
1415 end
1416
1417 def mapChildren
1418 Not.new(codeOrigin, (yield @child))
1419 end
1420
1421 def dump
1422 "(not #{child.dump})"
1423 end
1424end
1425
1426class Skip < NoChildren
1427 def initialize(codeOrigin)
1428 super(codeOrigin)
1429 end
1430
1431 def dump
1432 "\tskip"
1433 end
1434end
1435
1436class IfThenElse < Node
1437 attr_reader :predicate, :thenCase
1438 attr_accessor :elseCase
1439
1440 def initialize(codeOrigin, predicate, thenCase)
1441 super(codeOrigin)
1442 @predicate = predicate
1443 @thenCase = thenCase
1444 @elseCase = Skip.new(codeOrigin)
1445 end
1446
1447 def children
1448 if @elseCase
1449 [@predicate, @thenCase, @elseCase]
1450 else
1451 [@predicate, @thenCase]
1452 end
1453 end
1454
1455 def mapChildren
1456 ifThenElse = IfThenElse.new(codeOrigin, (yield @predicate), (yield @thenCase))
1457 ifThenElse.elseCase = yield @elseCase
1458 ifThenElse
1459 end
1460
1461 def dump
1462 "if #{predicate.dump}\n" + thenCase.dump + "\nelse\n" + elseCase.dump + "\nend"
1463 end
1464end
1465
1466class Macro < Node
1467 attr_reader :name, :variables, :body
1468
1469 def initialize(codeOrigin, name, variables, body)
1470 super(codeOrigin)
1471 @name = name
1472 @variables = variables
1473 @body = body
1474 end
1475
1476 def children
1477 @variables + [@body]
1478 end
1479
1480 def mapChildren
1481 Macro.new(codeOrigin, @name, @variables.map{|v| yield v}, (yield @body))
1482 end
1483
1484 def dump
1485 "macro #{name}(" + variables.collect{|v| v.dump}.join(", ") + ")\n" + body.dump + "\nend"
1486 end
1487end
1488
1489class MacroCall < Node
1490 attr_reader :name, :operands, :annotation
1491
1492 def initialize(codeOrigin, name, operands, annotation, originalName = nil)
1493 super(codeOrigin)
1494 @name = name
1495 @operands = operands
1496 raise unless @operands
1497 @operands.each{|v| raise unless v}
1498 @annotation = annotation
1499 @originalName = originalName
1500 end
1501
1502 def originalName
1503 @originalName || name
1504 end
1505
1506 def children
1507 @operands
1508 end
1509
1510 def mapChildren(&proc)
1511 MacroCall.new(codeOrigin, @name, @operands.map(&proc), @annotation, @originalName)
1512 end
1513
1514 def dump
1515 "\t#{originalName}(" + operands.collect{|v| v.dump}.join(", ") + ")"
1516 end
1517end
1518
Note: See TracBrowser for help on using the repository browser.