File: SILGenLocalArchetype.cpp

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (166 lines) | stat: -rw-r--r-- 5,747 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//===--- SILGenLocalArchetype.cpp - Local archetype transform -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the transformation which rewrites captured local
//  archetypes into primary archetypes in the enclosing function's generic
//  signature.
//
//===----------------------------------------------------------------------===//

#include "SILGen.h"
#include "swift/AST/LocalArchetypeRequirementCollector.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILCloner.h"

using namespace swift;
using namespace swift::Lowering;

namespace {

class LocalArchetypeTransform : public SILCloner<LocalArchetypeTransform> {
  friend class SILCloner<LocalArchetypeTransform>;
  friend class SILInstructionVisitor<LocalArchetypeTransform>;

  GenericSignatureWithCapturedEnvironments sig;
  GenericEnvironment *env;
  SubstitutionMap subs;

public:
  LocalArchetypeTransform(SILFunction *F,
                          GenericSignatureWithCapturedEnvironments sig)
      : SILCloner(*F), env(sig.genericSig.getGenericEnvironment()) {

    assert(!sig.capturedEnvs.empty() && "Why are we doing this?");

    // The primary archetypes of the old generic environment map to
    // primary archetypes of the new generic environment at the same
    // index and depth.
    subs = env->getForwardingSubstitutionMap();

    // Local archetypes map to generic parameters at higher depths.
    MapLocalArchetypesOutOfContext mapOutOfContext(sig.baseGenericSig,
                                                   sig.capturedEnvs);

    // For each captured environment...
    for (auto *capturedEnv : sig.capturedEnvs) {
      // For each introduced generic parameter...
      auto localParams = capturedEnv->getGenericSignature()
          .getInnermostGenericParams();
      for (auto *gp : localParams) {
        // Get the local archetype from the captured environment.
        auto origArchetypeTy = capturedEnv->mapTypeIntoContext(gp)
            ->castTo<LocalArchetypeType>();

        // Map the local archetype to an interface type in the new generic
        // signature.
        auto substInterfaceTy = mapOutOfContext(origArchetypeTy);

        // Map this interface type into the new generic environment to get
        // a primary archetype.
        auto substArchetypeTy = env->mapTypeIntoContext(substInterfaceTy)
            ->castTo<PrimaryArchetypeType>();

        // Remember this correspondence.
        registerLocalArchetypeRemapping(origArchetypeTy, substArchetypeTy);
      }
    }
  }

  SILType remapType(SILType Ty) {
    return Ty.subst(Builder.getModule().Types, subs);
  }

  CanType remapASTType(CanType ty) {
    return ty.subst(subs)->getCanonicalType();
  }

  ProtocolConformanceRef remapConformance(Type Ty, ProtocolConformanceRef C) {
    return C.subst(Ty, subs);
  }

  SubstitutionMap remapSubstitutionMap(SubstitutionMap subMap) {
    return subMap.subst(subs);
  }

  void doIt() {
    auto &F = getBuilder().getFunction();

    // Collect the old basic blocks that we're going to delete.
    llvm::SmallVector<SILBasicBlock *, 4> bbs;
    for (auto &bb : F)
      bbs.push_back(&bb);

    // Make F.mapTypeIntoContext() use the new environment.
    F.setGenericEnvironment(env);

    // Start by cloning the entry block.
    auto *origEntryBlock = F.getEntryBlock();
    auto *clonedEntryBlock = F.createBasicBlock();

    // Clone arguments.
    SmallVector<SILValue, 4> entryArgs;
    entryArgs.reserve(origEntryBlock->getArguments().size());
    for (auto &origArg : origEntryBlock->getArguments()) {

      // Remap the argument type into the new generic environment.
      SILType mappedType = getOpType(origArg->getType());
      auto *NewArg = clonedEntryBlock->createFunctionArgument(
          mappedType, origArg->getDecl(), true);
      NewArg->copyFlags(cast<SILFunctionArgument>(origArg));
      entryArgs.push_back(NewArg);
    }

    // Clone the remaining body.
    getBuilder().setInsertionPoint(clonedEntryBlock);
    cloneFunctionBody(&F, clonedEntryBlock, entryArgs,
                      true /*replaceOriginalFunctionInPlace*/);

    // Insert the new entry block at the beginning.
    F.moveBlockBefore(clonedEntryBlock, F.begin());

    // FIXME: This should be a common utility.

    // Erase the old basic blocks.
    for (auto *bb : bbs) {
      for (SILArgument *arg : bb->getArguments()) {
        arg->replaceAllUsesWithUndef();
        // To appease the ownership verifier, just set to None.
        arg->setOwnershipKind(OwnershipKind::None);
      }

      // Instructions in the dead block may be used by other dead blocks. Replace
      // any uses of them with undef values.
      while (!bb->empty()) {
        // Grab the last instruction in the bb.
        auto *inst = &bb->back();

        // Replace any still-remaining uses with undef values and erase.
        inst->replaceAllUsesOfAllResultsWithUndef();
        inst->eraseFromParent();
      }

      // Finally, erase the basic block itself.
      bb->eraseFromParent();
    }
  }
};

} // end anonymous namespace

void SILGenModule::recontextualizeCapturedLocalArchetypes(
    SILFunction *F, GenericSignatureWithCapturedEnvironments sig) {
  if (sig.capturedEnvs.empty())
    return;

  LocalArchetypeTransform(F, sig).doIt();
  M.reclaimUnresolvedLocalArchetypeDefinitions();
}