aliases.nim 5.8 KB

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