asm.rb 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #!/usr/bin/env ruby
  2. # Copyright (C) 2011 Apple Inc. All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions
  6. # are met:
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # 2. Redistributions in binary form must reproduce the above copyright
  10. # notice, this list of conditions and the following disclaimer in the
  11. # documentation and/or other materials provided with the distribution.
  12. #
  13. # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
  14. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  15. # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
  17. # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  23. # THE POSSIBILITY OF SUCH DAMAGE.
  24. $: << File.dirname(__FILE__)
  25. require "config"
  26. require "backends"
  27. require "digest/sha1"
  28. require "offsets"
  29. require "parser"
  30. require "self_hash"
  31. require "settings"
  32. require "transform"
  33. class Assembler
  34. def initialize(outp)
  35. @outp = outp
  36. @state = :cpp
  37. @commentState = :none
  38. @comment = nil
  39. @internalComment = nil
  40. @annotation = nil
  41. @codeOrigin = nil
  42. @numLocalLabels = 0
  43. @numGlobalLabels = 0
  44. @newlineSpacerState = :none
  45. end
  46. def enterAsm
  47. @outp.puts "OFFLINE_ASM_BEGIN"
  48. @state = :asm
  49. end
  50. def leaveAsm
  51. putsLastComment
  52. @outp.puts "OFFLINE_ASM_END"
  53. @state = :cpp
  54. end
  55. def inAsm
  56. enterAsm
  57. yield
  58. leaveAsm
  59. end
  60. # Concatenates all the various components of the comment to dump.
  61. def lastComment
  62. separator = " "
  63. result = ""
  64. result = "#{@comment}" if @comment
  65. if @annotation and $enableInstrAnnotations
  66. result += separator if result != ""
  67. result += "#{@annotation}"
  68. end
  69. if @internalComment
  70. result += separator if result != ""
  71. result += "#{@internalComment}"
  72. end
  73. if @codeOrigin and $enableCodeOriginComments
  74. result += separator if result != ""
  75. result += "#{@codeOrigin}"
  76. end
  77. if result != ""
  78. result = "// " + result
  79. end
  80. # Reset all the components that we've just sent to be dumped.
  81. @commentState = :none
  82. @comment = nil
  83. @annotation = nil
  84. @codeOrigin = nil
  85. @internalComment = nil
  86. result
  87. end
  88. # Puts a C Statement in the output stream.
  89. def putc(*line)
  90. raise unless @state == :asm
  91. @outp.puts(formatDump(" " + line.join(''), lastComment))
  92. end
  93. def formatDump(dumpStr, comment, commentColumns=$preferredCommentStartColumn)
  94. if comment.length > 0
  95. "%-#{commentColumns}s %s" % [dumpStr, comment]
  96. else
  97. dumpStr
  98. end
  99. end
  100. # private method for internal use only.
  101. def putAnnotation(text)
  102. raise unless @state == :asm
  103. if $enableInstrAnnotations
  104. @outp.puts text
  105. @annotation = nil
  106. end
  107. end
  108. def putLocalAnnotation()
  109. putAnnotation " // #{@annotation}" if @annotation
  110. end
  111. def putGlobalAnnotation()
  112. putsNewlineSpacerIfAppropriate(:annotation)
  113. putAnnotation "// #{@annotation}" if @annotation
  114. end
  115. def putsLastComment
  116. comment = lastComment
  117. unless comment.empty?
  118. @outp.puts comment
  119. end
  120. end
  121. def puts(*line)
  122. raise unless @state == :asm
  123. @outp.puts(formatDump(" \"\\t" + line.join('') + "\\n\"", lastComment))
  124. end
  125. def print(line)
  126. raise unless @state == :asm
  127. @outp.print("\"" + line + "\"")
  128. end
  129. def putsNewlineSpacerIfAppropriate(state)
  130. if @newlineSpacerState != state
  131. @outp.puts("\n")
  132. @newlineSpacerState = state
  133. end
  134. end
  135. def putsLabel(labelName)
  136. raise unless @state == :asm
  137. @numGlobalLabels += 1
  138. putsNewlineSpacerIfAppropriate(:global)
  139. @internalComment = $enableLabelCountComments ? "Global Label #{@numGlobalLabels}" : nil
  140. if /\Allint_op_/.match(labelName)
  141. @outp.puts(formatDump("OFFLINE_ASM_OPCODE_LABEL(op_#{$~.post_match})", lastComment))
  142. else
  143. @outp.puts(formatDump("OFFLINE_ASM_GLUE_LABEL(#{labelName})", lastComment))
  144. end
  145. @newlineSpacerState = :none # After a global label, we can use another spacer.
  146. end
  147. def putsLocalLabel(labelName)
  148. raise unless @state == :asm
  149. @numLocalLabels += 1
  150. @outp.puts("\n")
  151. @internalComment = $enableLabelCountComments ? "Local Label #{@numLocalLabels}" : nil
  152. @outp.puts(formatDump(" OFFLINE_ASM_LOCAL_LABEL(#{labelName})", lastComment))
  153. end
  154. def self.labelReference(labelName)
  155. "\" LOCAL_REFERENCE(#{labelName}) \""
  156. end
  157. def self.localLabelReference(labelName)
  158. "\" LOCAL_LABEL_STRING(#{labelName}) \""
  159. end
  160. def self.cLabelReference(labelName)
  161. if /\Allint_op_/.match(labelName)
  162. "op_#{$~.post_match}" # strip opcodes of their llint_ prefix.
  163. else
  164. "#{labelName}"
  165. end
  166. end
  167. def self.cLocalLabelReference(labelName)
  168. "#{labelName}"
  169. end
  170. def codeOrigin(text)
  171. case @commentState
  172. when :none
  173. @codeOrigin = text
  174. @commentState = :one
  175. when :one
  176. if $enableCodeOriginComments
  177. @outp.puts " // #{@codeOrigin}"
  178. @outp.puts " // #{text}"
  179. end
  180. @codeOrigin = nil
  181. @commentState = :many
  182. when :many
  183. @outp.puts "// #{text}" if $enableCodeOriginComments
  184. else
  185. raise
  186. end
  187. end
  188. def comment(text)
  189. @comment = text
  190. end
  191. def annotation(text)
  192. @annotation = text
  193. end
  194. end
  195. asmFile = ARGV.shift
  196. offsetsFile = ARGV.shift
  197. outputFlnm = ARGV.shift
  198. $stderr.puts "offlineasm: Parsing #{asmFile} and #{offsetsFile} and creating assembly file #{outputFlnm}."
  199. begin
  200. configurationList = offsetsAndConfigurationIndex(offsetsFile)
  201. rescue MissingMagicValuesException
  202. $stderr.puts "offlineasm: No magic values found. Skipping assembly file generation."
  203. exit 0
  204. end
  205. inputHash =
  206. "// offlineasm input hash: " + parseHash(asmFile) +
  207. " " + Digest::SHA1.hexdigest(configurationList.map{|v| (v[0] + [v[1]]).join(' ')}.join(' ')) +
  208. " " + selfHash
  209. if FileTest.exist? outputFlnm
  210. File.open(outputFlnm, "r") {
  211. | inp |
  212. firstLine = inp.gets
  213. if firstLine and firstLine.chomp == inputHash
  214. $stderr.puts "offlineasm: Nothing changed."
  215. exit 0
  216. end
  217. }
  218. end
  219. File.open(outputFlnm, "w") {
  220. | outp |
  221. $output = outp
  222. $output.puts inputHash
  223. $asm = Assembler.new($output)
  224. ast = parse(asmFile)
  225. configurationList.each {
  226. | configuration |
  227. offsetsList = configuration[0]
  228. configIndex = configuration[1]
  229. forSettings(computeSettingsCombinations(ast)[configIndex], ast) {
  230. | concreteSettings, lowLevelAST, backend |
  231. lowLevelAST = lowLevelAST.resolve(*buildOffsetsMap(lowLevelAST, offsetsList))
  232. lowLevelAST.validate
  233. emitCodeInConfiguration(concreteSettings, lowLevelAST, backend) {
  234. $asm.inAsm {
  235. lowLevelAST.lower(backend)
  236. }
  237. }
  238. }
  239. }
  240. }
  241. $stderr.puts "offlineasm: Assembly file #{outputFlnm} successfully generated."