aliases.nim 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Simple alias analysis for the HLO and the code generators.
  10. import
  11. ast, astalgo, types, trees, intsets
  12. when defined(nimPreviewSlimSystem):
  13. import std/assertions
  14. type
  15. TAnalysisResult* = enum
  16. arNo, arMaybe, arYes
  17. proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult
  18. proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
  19. result = arNo
  20. case n.kind
  21. of nkRecList:
  22. for i in 0..<n.len:
  23. result = isPartOfAux(n[i], b, marker)
  24. if result == arYes: return
  25. of nkRecCase:
  26. assert(n[0].kind == nkSym)
  27. result = isPartOfAux(n[0], b, marker)
  28. if result == arYes: return
  29. for i in 1..<n.len:
  30. case n[i].kind
  31. of nkOfBranch, nkElse:
  32. result = isPartOfAux(lastSon(n[i]), b, marker)
  33. if result == arYes: return
  34. else: discard "isPartOfAux(record case branch)"
  35. of nkSym:
  36. result = isPartOfAux(n.sym.typ, b, marker)
  37. else: discard
  38. proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
  39. result = arNo
  40. if a == nil or b == nil: return
  41. if containsOrIncl(marker, a.id): return
  42. if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
  43. case a.kind
  44. of tyObject:
  45. if a[0] != nil:
  46. result = isPartOfAux(a[0].skipTypes(skipPtrs), b, marker)
  47. if result == arNo: result = isPartOfAux(a.n, b, marker)
  48. of tyGenericInst, tyDistinct, tyAlias, tySink:
  49. result = isPartOfAux(lastSon(a), b, marker)
  50. of tyArray, tySet, tyTuple:
  51. for i in 0..<a.len:
  52. result = isPartOfAux(a[i], b, marker)
  53. if result == arYes: return
  54. else: discard
  55. proc isPartOf(a, b: PType): TAnalysisResult =
  56. ## checks iff 'a' can be part of 'b'. Iterates over VALUE types!
  57. var marker = initIntSet()
  58. # watch out: parameters reversed because I'm too lazy to change the code...
  59. result = isPartOfAux(b, a, marker)
  60. proc isPartOf*(a, b: PNode): TAnalysisResult =
  61. ## checks if location `a` can be part of location `b`. We treat seqs and
  62. ## strings as pointers because the code gen often just passes them as such.
  63. ##
  64. ## Note: `a` can only be part of `b`, if `a`'s type can be part of `b`'s
  65. ## type. Since however type analysis is more expensive, we perform it only
  66. ## if necessary.
  67. ##
  68. ## cases:
  69. ##
  70. ## YES-cases:
  71. ## ```
  72. ## x <| x # for general trees
  73. ## x[] <| x
  74. ## x[i] <| x
  75. ## x.f <| x
  76. ## ```
  77. ##
  78. ## NO-cases:
  79. ## ```
  80. ## x !<| y # depending on type and symbol kind
  81. ## x[constA] !<| x[constB]
  82. ## x.f !<| x.g
  83. ## x.f !<| y.f iff x !<= y
  84. ## ```
  85. ##
  86. ## MAYBE-cases:
  87. ##
  88. ## ```
  89. ## x[] ?<| y[] iff compatible type
  90. ##
  91. ##
  92. ## x[] ?<| y depending on type
  93. ## ```
  94. if a.kind == b.kind:
  95. case a.kind
  96. of nkSym:
  97. const varKinds = {skVar, skTemp, skProc, skFunc}
  98. # same symbol: aliasing:
  99. if a.sym.id == b.sym.id: result = arYes
  100. elif a.sym.kind in varKinds or b.sym.kind in varKinds:
  101. # actually, a param could alias a var but we know that cannot happen
  102. # here. XXX make this more generic
  103. result = arNo
  104. else:
  105. # use expensive type check:
  106. if isPartOf(a.sym.typ, b.sym.typ) != arNo:
  107. result = arMaybe
  108. of nkBracketExpr:
  109. result = isPartOf(a[0], b[0])
  110. if a.len >= 2 and b.len >= 2:
  111. # array accesses:
  112. if result == arYes and isDeepConstExpr(a[1]) and isDeepConstExpr(b[1]):
  113. # we know it's the same array and we have 2 constant indexes;
  114. # if they are
  115. var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1]
  116. var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1]
  117. if sameValue(x, y): result = arYes
  118. else: result = arNo
  119. # else: maybe and no are accurate
  120. else:
  121. # pointer derefs:
  122. if result != arYes:
  123. if isPartOf(a.typ, b.typ) != arNo: result = arMaybe
  124. of nkDotExpr:
  125. result = isPartOf(a[0], b[0])
  126. if result != arNo:
  127. # if the fields are different, it's not the same location
  128. if a[1].sym.id != b[1].sym.id:
  129. result = arNo
  130. of nkHiddenDeref, nkDerefExpr:
  131. result = isPartOf(a[0], b[0])
  132. # weaken because of indirection:
  133. if result != arYes:
  134. if isPartOf(a.typ, b.typ) != arNo: result = arMaybe
  135. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  136. result = isPartOf(a[1], b[1])
  137. of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
  138. result = isPartOf(a[0], b[0])
  139. else: discard
  140. # Calls return a new location, so a default of ``arNo`` is fine.
  141. else:
  142. # go down recursively; this is quite demanding:
  143. const
  144. Ix0Kinds = {nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
  145. nkCheckedFieldExpr, nkHiddenAddr}
  146. Ix1Kinds = {nkHiddenStdConv, nkHiddenSubConv, nkConv}
  147. DerefKinds = {nkHiddenDeref, nkDerefExpr}
  148. case b.kind
  149. of Ix0Kinds:
  150. # a* !<| b.f iff a* !<| b
  151. result = isPartOf(a, b[0])
  152. of DerefKinds:
  153. # a* !<| b[] iff
  154. if isPartOf(a.typ, b.typ) != arNo:
  155. result = isPartOf(a, b[0])
  156. if result == arNo: result = arMaybe
  157. of Ix1Kinds:
  158. # a* !<| T(b) iff a* !<| b
  159. result = isPartOf(a, b[1])
  160. of nkSym:
  161. # b is an atom, so we have to check a:
  162. case a.kind
  163. of Ix0Kinds:
  164. # a.f !<| b* iff a.f !<| b*
  165. result = isPartOf(a[0], b)
  166. of Ix1Kinds:
  167. result = isPartOf(a[1], b)
  168. of DerefKinds:
  169. if isPartOf(a.typ, b.typ) != arNo:
  170. result = isPartOf(a[0], b)
  171. if result == arNo: result = arMaybe
  172. else: discard
  173. of nkObjConstr:
  174. result = arNo
  175. for i in 1..<b.len:
  176. let res = isPartOf(a, b[i][1])
  177. if res != arNo:
  178. result = res
  179. if res == arYes: break
  180. of nkCallKinds:
  181. result = arNo
  182. for i in 1..<b.len:
  183. let res = isPartOf(a, b[i])
  184. if res != arNo:
  185. result = res
  186. if res == arYes: break
  187. of nkBracket:
  188. if b.len > 0:
  189. result = isPartOf(a, b[0])
  190. else: discard