<commit_before>/// Schedule.swift
///
/// Copyright 2017-2018, The Silt Language Project.
///
/// This project is released under the MIT license, a copy of which is
/// available in the repository.

import Seismography

/// A schedule adds SSA-like operations before a CPS-style call. 
public final class Schedule {
  /// Whether this operation is scheduled early (before the 'terminator'), or
  /// late (after the 'terminator').
  public enum Tag {
    case early
    case late
  }

  /// A 'block' abstraction that 
  public final class Block: Equatable, Hashable {
    public internal(set) var parent: Continuation
    public internal(set)var primops: [PrimOp]
    public internal(set)var index: Int

    init(_ parent: Continuation, _ primops: [PrimOp], _ idx: Int) {
      self.parent = parent
      self.primops = primops
      self.index = idx
    }

    public static func == (lhs: Block, rhs: Block) -> Bool {
      return lhs === rhs
    }

    public func hash(into hasher: inout Hasher) {
      return "\(ObjectIdentifier(self).hashValue)".hash(into: &hasher)
    }
  }

  public let scope: Scope
  public let tag: Tag
  public internal(set) var blocks: [Block] = []
  var indices: [Continuation: Int] = [:]
  public init(_ scope: Scope, _ tag: Tag) {
    self.scope = scope
    self.tag = tag

    var i = 0
    for n in scope.reversePostOrder {
      defer { i += 1 }
      self.blocks.append(Block(n, [], i))
      self.indices[n] = i
    }
    for n in scope.continuations where self.indices[n] == nil {
      defer { i += 1 }
      self.blocks.append(Block(n, [], i))
      self.indices[n] = i
    }
    _ = Scheduler(self)
  }

  func block(_ c: Continuation) -> Block {
    return self.blocks[self.indices[c]!]
  }

  func dump() {
    for block in self.blocks {
      block.parent.dump()
      for primop in block.primops {
        primop.dump()
      }
    }
  }
}

private final class Scheduler {
  let scope: Scope
  let schedule: Schedule

  init(_ schedule: Schedule) {
    self.scope = schedule.scope
    self.schedule = schedule
    switch schedule.tag {
    case .early:
      for cont in self.scope.continuations {
        guard let terminal = cont.terminalOp else { continue }
        self.schedulePrimopsEarly(in: cont, terminal)
      }
    case .late:
      fatalError()
    }
  }

  func schedulePrimopsEarly(in cont: Continuation, _ term: TerminalOp) {
    var queue = [PrimOp]()
    var visited = Set<Value>()
    var schedule = [PrimOp]()

    queue.append(term)

    while let op = queue.popLast() {
      guard visited.insert(op).inserted else { continue }
      schedule.append(op)

      for operand in op.operands {
        guard let prim = operand.value as? PrimOp else { continue }
        queue.append(prim)
      }
    }
    let activeBlock = self.schedule.block(cont)
    for s in schedule.reversed().dropLast() {
      activeBlock.primops.append(s)
    }
    for cleanup in cont.cleanups {
      activeBlock.primops.append(cleanup)
    }
    activeBlock.primops.append(term)
  }
}<commit_msg>Deduplicate primops in the final schedule<commit_after>/// Schedule.swift
///
/// Copyright 2017-2018, The Silt Language Project.
///
/// This project is released under the MIT license, a copy of which is
/// available in the repository.

import Seismography

/// A schedule adds SSA-like operations before a CPS-style call. 
public final class Schedule {
  /// Whether this operation is scheduled early (before the 'terminator'), or
  /// late (after the 'terminator').
  public enum Tag {
    case early
    case late
  }

  /// A 'block' abstraction that 
  public final class Block: Equatable, Hashable {
    public internal(set) var parent: Continuation
    public internal(set) var primops: [PrimOp]
    public internal(set) var index: Int

    init(_ parent: Continuation, _ primops: [PrimOp], _ idx: Int) {
      self.parent = parent
      self.primops = primops
      self.index = idx
    }

    public static func == (lhs: Block, rhs: Block) -> Bool {
      return lhs === rhs
    }

    public func hash(into hasher: inout Hasher) {
      return "\(ObjectIdentifier(self).hashValue)".hash(into: &hasher)
    }
  }

  public let scope: Scope
  public let tag: Tag
  public internal(set) var blocks: [Block] = []
  var indices: [Continuation: Int] = [:]
  public init(_ scope: Scope, _ tag: Tag) {
    self.scope = scope
    self.tag = tag

    var i = 0
    for n in scope.reversePostOrder {
      defer { i += 1 }
      self.blocks.append(Block(n, [], i))
      self.indices[n] = i
    }
    for n in scope.continuations where self.indices[n] == nil {
      defer { i += 1 }
      self.blocks.append(Block(n, [], i))
      self.indices[n] = i
    }
    _ = Scheduler(self)
  }

  func block(_ c: Continuation) -> Block {
    return self.blocks[self.indices[c]!]
  }

  func dump() {
    for block in self.blocks {
      block.parent.dump()
      for primop in block.primops {
        primop.dump()
      }
    }
  }
}

private final class Scheduler {
  let scope: Scope
  let schedule: Schedule

  init(_ schedule: Schedule) {
    self.scope = schedule.scope
    self.schedule = schedule
    switch schedule.tag {
    case .early:
      for cont in self.scope.continuations {
        guard let terminal = cont.terminalOp else { continue }
        self.schedulePrimopsEarly(in: cont, terminal)
      }
    case .late:
      fatalError()
    }
  }

  func schedulePrimopsEarly(in cont: Continuation, _ term: TerminalOp) {
    var queue = [PrimOp]()
    var visited = Set<Value>()
    var schedule = [PrimOp]()

    queue.append(term)

    while let op = queue.popLast() {
      schedule.append(op)

      for operand in op.operands {
        guard let prim = operand.value as? PrimOp else { continue }
        queue.append(prim)
      }
    }
    let activeBlock = self.schedule.block(cont)
    for s in schedule.reversed().dropLast() {
      guard visited.insert(s).inserted else {
        continue
      }
      activeBlock.primops.append(s)
    }
    for cleanup in cont.cleanups {
      activeBlock.primops.append(cleanup)
    }
    activeBlock.primops.append(term)
  }
}
{'fraction_non_alphanumeric': 0.11363265306122448, 'fraction_numerical': 0.0035918367346938775, 'mean_word_length': 2.461016949152542, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5877674', 'n_tokens_mistral': 1941, 'n_tokens_neox': 1869, 'n_words': 569}