Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : #include "llvm-version.h"
4 : :
5 : : #include <llvm/IR/Module.h>
6 : : #include <llvm/IR/Verifier.h>
7 : : #include <llvm/IR/Constants.h>
8 : : #include <llvm/IR/Instructions.h>
9 : : #include <llvm/IR/InstIterator.h>
10 : : #include <llvm/IR/LegacyPassManager.h>
11 : : #include <llvm/Support/Debug.h>
12 : : #include <llvm/Transforms/Utils/Cloning.h>
13 : : #include <llvm/Transforms/Utils/ValueMapper.h>
14 : :
15 : : #include "codegen_shared.h"
16 : : #include "julia.h"
17 : : #include "passes.h"
18 : :
19 : : #define DEBUG_TYPE "remove_addrspaces"
20 : :
21 : : using namespace llvm;
22 : :
23 : : using AddrspaceRemapFunction = std::function<unsigned(unsigned)>;
24 : :
25 : :
26 : : //
27 : : // Helpers
28 : : //
29 : :
30 : : class AddrspaceRemoveTypeRemapper : public ValueMapTypeRemapper {
31 : : AddrspaceRemapFunction ASRemapper;
32 : :
33 : : public:
34 : 49 : AddrspaceRemoveTypeRemapper(AddrspaceRemapFunction ASRemapper)
35 : 49 : : ASRemapper(ASRemapper)
36 : : {
37 : 49 : }
38 : :
39 : 19716 : Type *remapType(Type *SrcTy)
40 : : {
41 : : // If we already have an entry for this type, return it.
42 : 19716 : Type *DstTy = MappedTypes[SrcTy];
43 [ + + ]: 19716 : if (DstTy)
44 : 18634 : return DstTy;
45 : :
46 : 1082 : DstTy = SrcTy;
47 [ + + ]: 1082 : if (auto Ty = dyn_cast<PointerType>(SrcTy)) {
48 [ - + ]: 616 : if (Ty->isOpaque()) {
49 : 0 : DstTy = PointerType::get(Ty->getContext(), ASRemapper(Ty->getAddressSpace()));
50 : : }
51 : : else {
52 : : //Remove once opaque pointer transition is complete
53 : 1232 : DstTy = PointerType::get(
54 : 616 : remapType(Ty->getPointerElementType()),
55 : : ASRemapper(Ty->getAddressSpace()));
56 : : }
57 : : }
58 [ + + ]: 466 : else if (auto Ty = dyn_cast<FunctionType>(SrcTy)) {
59 : 60 : SmallVector<Type *, 4> Params;
60 [ + + ]: 135 : for (unsigned Index = 0; Index < Ty->getNumParams(); ++Index)
61 : 75 : Params.push_back(remapType(Ty->getParamType(Index)));
62 : 120 : DstTy = FunctionType::get(
63 : 120 : remapType(Ty->getReturnType()), Params, Ty->isVarArg());
64 : : }
65 [ + + ]: 406 : else if (auto Ty = dyn_cast<StructType>(SrcTy)) {
66 [ + - ]: 66 : if (Ty->isLiteral()) {
67 : : // Since a literal type has to have the body when it is created,
68 : : // we need to remap the element types first. This is safe only
69 : : // for literal types (i.e., no self-reference) and thus treated
70 : : // separately.
71 : : assert(!Ty->hasName()); // literal type has no name.
72 : 66 : SmallVector<Type *, 4> NewElTys;
73 : 66 : NewElTys.reserve(Ty->getNumElements());
74 [ + + ]: 115 : for (auto E: Ty->elements())
75 : 49 : NewElTys.push_back(remapType(E));
76 : 66 : DstTy = StructType::get(Ty->getContext(), NewElTys, Ty->isPacked());
77 [ # # ]: 0 : } else if (!Ty->isOpaque()) {
78 : : // If the struct type is not literal and not opaque, it can have
79 : : // self-referential fields (i.e., pointer type of itself as a
80 : : // field).
81 : 0 : StructType *DstTy_ = StructType::create(Ty->getContext());
82 [ # # ]: 0 : if (Ty->hasName()) {
83 : 0 : auto Name = std::string(Ty->getName());
84 : 0 : Ty->setName(Name + ".bad");
85 : 0 : DstTy_->setName(Name);
86 : : }
87 : : // To avoid infinite recursion, shove the placeholder of the DstTy before
88 : : // recursing into the element types:
89 : 0 : MappedTypes[SrcTy] = DstTy_;
90 : :
91 : 0 : auto Els = Ty->getNumElements();
92 : 0 : SmallVector<Type *, 4> NewElTys(Els);
93 [ # # ]: 0 : for (unsigned i = 0; i < Els; ++i)
94 : 0 : NewElTys[i] = remapType(Ty->getElementType(i));
95 : 0 : DstTy_->setBody(NewElTys, Ty->isPacked());
96 : 0 : DstTy = DstTy_;
97 : : }
98 : : }
99 [ + + ]: 340 : else if (auto Ty = dyn_cast<ArrayType>(SrcTy))
100 : 116 : DstTy = ArrayType::get(
101 : 58 : remapType(Ty->getElementType()), Ty->getNumElements());
102 [ + + ]: 282 : else if (auto Ty = dyn_cast<VectorType>(SrcTy))
103 : 1 : DstTy = VectorType::get(remapType(Ty->getElementType()), Ty);
104 : :
105 : 1082 : if (DstTy != SrcTy)
106 : : LLVM_DEBUG(
107 : : dbgs() << "Remapping type:\n"
108 : : << " from " << *SrcTy << "\n"
109 : : << " to " << *DstTy << "\n");
110 : :
111 : 1082 : MappedTypes[SrcTy] = DstTy;
112 : 1082 : return DstTy;
113 : : }
114 : :
115 : : private:
116 : : DenseMap<Type *, Type *> MappedTypes;
117 : : };
118 : :
119 : :
120 : : class AddrspaceRemoveValueMaterializer : public ValueMaterializer {
121 : : ValueToValueMapTy &VM;
122 : : RemapFlags Flags;
123 : : ValueMapTypeRemapper *TypeMapper = nullptr;
124 : :
125 : : public:
126 : 49 : AddrspaceRemoveValueMaterializer(
127 : : ValueToValueMapTy &VM,
128 : : RemapFlags Flags = RF_None,
129 : : ValueMapTypeRemapper *TypeMapper = nullptr)
130 : 49 : : VM(VM), Flags(Flags), TypeMapper(TypeMapper)
131 : : {
132 : 49 : }
133 : :
134 : 2198 : Value *materialize(Value *SrcV)
135 : : {
136 : 2198 : Value *DstV = nullptr;
137 [ + + ]: 2198 : if (auto CE = dyn_cast<ConstantExpr>(SrcV)) {
138 : 765 : Type *Ty = remapType(CE->getType());
139 [ + + ]: 765 : if (CE->getOpcode() == Instruction::AddrSpaceCast) {
140 : : // peek through addrspacecasts if their address spaces match
141 : : // (like RemoveNoopAddrSpaceCasts, but for const exprs)
142 : 312 : Constant *Src = mapConstant(CE->getOperand(0));
143 [ + - ]: 624 : if (Src->getType()->getPointerAddressSpace() ==
144 : 312 : Ty->getPointerAddressSpace())
145 : 312 : DstV = Src;
146 : : }
147 : : else {
148 : : // recreate other const exprs with their operands remapped
149 : 906 : SmallVector<Constant *, 4> Ops;
150 [ + + ]: 918 : for (unsigned Index = 0; Index < CE->getNumOperands();
151 : : ++Index) {
152 : 465 : Constant *Op = CE->getOperand(Index);
153 : 465 : Constant *NewOp = mapConstant(Op);
154 [ + - ]: 465 : Ops.push_back(NewOp ? cast<Constant>(NewOp) : Op);
155 : : }
156 : :
157 [ + + ]: 453 : if (CE->getOpcode() == Instruction::GetElementPtr) {
158 : : // GEP const exprs need to know the type of the source.
159 : : // asserts remapType(typeof arg0) == typeof mapValue(arg0).
160 : 6 : Constant *Src = CE->getOperand(0);
161 : 6 : auto ptrty = cast<PointerType>(Src->getType()->getScalarType());
162 : : //Remove once opaque pointer transition is complete
163 [ + - ]: 6 : if (!ptrty->isOpaque()) {
164 : 6 : Type *SrcTy = remapType(ptrty->getPointerElementType());
165 : 6 : DstV = CE->getWithOperands(Ops, Ty, false, SrcTy);
166 : : }
167 : : }
168 : : else
169 : 447 : DstV = CE->getWithOperands(Ops, Ty);
170 : : }
171 : : }
172 : :
173 : : if (DstV)
174 : : LLVM_DEBUG(
175 : : dbgs() << "Materializing value:\n"
176 : : << " from " << *SrcV << "\n"
177 : : << " to " << *DstV << "\n");
178 : 2198 : return DstV;
179 : : }
180 : :
181 : : private:
182 : 771 : Type *remapType(Type *SrcTy)
183 : : {
184 [ + - ]: 771 : if (TypeMapper)
185 : 771 : return TypeMapper->remapType(SrcTy);
186 : : else
187 : 0 : return SrcTy;
188 : : }
189 : :
190 : : Value *mapValue(Value *V)
191 : : {
192 : : return MapValue(V, VM, Flags, TypeMapper, this);
193 : : }
194 : :
195 : 777 : Constant *mapConstant(Constant *V)
196 : : {
197 : 777 : return MapValue(V, VM, Flags, TypeMapper, this);
198 : : }
199 : : };
200 : :
201 : 113 : bool RemoveNoopAddrSpaceCasts(Function *F)
202 : : {
203 : 113 : bool Changed = false;
204 : :
205 : 113 : SmallVector<AddrSpaceCastInst *, 4> NoopCasts;
206 [ + + ]: 8684 : for (Instruction &I : instructions(F)) {
207 [ + + ]: 8571 : if (auto *ASC = dyn_cast<AddrSpaceCastInst>(&I)) {
208 [ + - ]: 306 : if (ASC->getSrcAddressSpace() == ASC->getDestAddressSpace()) {
209 : : LLVM_DEBUG(
210 : : dbgs() << "Removing noop address space cast:\n"
211 : : << I << "\n");
212 : 306 : ASC->replaceAllUsesWith(ASC->getOperand(0));
213 : 306 : NoopCasts.push_back(ASC);
214 : : }
215 : : }
216 : : }
217 [ + + ]: 419 : for (auto &I : NoopCasts)
218 : 306 : I->eraseFromParent();
219 : :
220 : 113 : return Changed;
221 : : }
222 : :
223 : 129 : static void copyComdat(GlobalObject *Dst, const GlobalObject *Src)
224 : : {
225 : 129 : const Comdat *SC = Src->getComdat();
226 [ + - ]: 129 : if (!SC)
227 : 129 : return;
228 : 0 : Comdat *DC = Dst->getParent()->getOrInsertComdat(SC->getName());
229 : 0 : DC->setSelectionKind(SC->getSelectionKind());
230 : 0 : Dst->setComdat(DC);
231 : : }
232 : :
233 : :
234 : : //
235 : : // Actual pass
236 : : //
237 : :
238 : 0 : unsigned removeAllAddrspaces(unsigned AS)
239 : : {
240 : 0 : return AddressSpace::Generic;
241 : : }
242 : :
243 : 49 : bool removeAddrspaces(Module &M, AddrspaceRemapFunction ASRemapper)
244 : : {
245 : 98 : ValueToValueMapTy VMap;
246 : 98 : AddrspaceRemoveTypeRemapper TypeRemapper(ASRemapper);
247 : : AddrspaceRemoveValueMaterializer Materializer(
248 : 49 : VMap, RF_None, &TypeRemapper);
249 : :
250 : : // Loop over all of the global variables, creating versions without address
251 : : // spaces. We only add the new globals to the VMap, attributes and
252 : : // initializers come later.
253 : 98 : SmallVector<GlobalVariable *, 4> Globals;
254 [ + + ]: 71 : for (auto &GV : M.globals())
255 : 22 : Globals.push_back(&GV);
256 [ + + ]: 71 : for (auto &GV : Globals) {
257 : 22 : std::string Name;
258 [ + + ]: 22 : if (GV->hasName()) {
259 : 14 : Name = std::string(GV->getName());
260 : 14 : GV->setName(Name + ".bad");
261 : : }
262 : : else
263 : 8 : Name = "";
264 : :
265 : : GlobalVariable *NGV = new GlobalVariable(
266 : : M,
267 : 22 : TypeRemapper.remapType(GV->getValueType()),
268 : 22 : GV->isConstant(),
269 : 22 : GV->getLinkage(),
270 : : (Constant *)nullptr,
271 : : Name,
272 : : (GlobalVariable *)nullptr,
273 : 22 : GV->getThreadLocalMode(),
274 : 22 : GV->getType()->getAddressSpace());
275 : 22 : NGV->copyAttributesFrom(GV);
276 : 22 : VMap[GV] = NGV;
277 : : }
278 : :
279 : : // Loop over the aliases in the module.
280 : 98 : SmallVector<GlobalAlias *, 4> Aliases;
281 [ - + ]: 49 : for (auto &GA : M.aliases())
282 : 0 : Aliases.push_back(&GA);
283 [ - + ]: 49 : for (auto &GA : Aliases) {
284 : 0 : std::string Name;
285 [ # # ]: 0 : if (GA->hasName()) {
286 : 0 : Name = std::string(GA->getName());
287 : 0 : GA->setName(Name + ".bad");
288 : : }
289 : : else
290 : 0 : Name = "";
291 : :
292 : 0 : auto *NGA = GlobalAlias::create(
293 : : TypeRemapper.remapType(GA->getValueType()),
294 : 0 : GA->getType()->getPointerAddressSpace(),
295 : : GA->getLinkage(),
296 : : Name,
297 : : &M);
298 : 0 : NGA->copyAttributesFrom(GA);
299 : 0 : VMap[GA] = NGA;
300 : : }
301 : :
302 : : // Loop over the functions in the module, creating new ones as before.
303 : 49 : SmallVector<Function *, 4> Functions;
304 [ + + ]: 824 : for (Function &F : M)
305 : 775 : Functions.push_back(&F);
306 [ + + ]: 824 : for (Function *F : Functions) {
307 : 1550 : std::string Name;
308 [ + - ]: 775 : if (F->hasName()) {
309 : 775 : Name = std::string(F->getName());
310 : 775 : F->setName(Name + ".bad");
311 : : }
312 : : else
313 : 0 : Name = "";
314 : :
315 : 775 : FunctionType *FTy = cast<FunctionType>(F->getValueType());
316 : 775 : SmallVector<Type *, 3> Tys;
317 [ + + ]: 2299 : for (Type *Ty : FTy->params())
318 : 1524 : Tys.push_back(TypeRemapper.remapType(Ty));
319 : 775 : FunctionType *NFTy = FunctionType::get(
320 : : TypeRemapper.remapType(FTy->getReturnType()),
321 : : Tys,
322 : 775 : FTy->isVarArg());
323 : :
324 : 775 : Function *NF = Function::Create(
325 : : NFTy, F->getLinkage(), F->getAddressSpace(), Name, &M);
326 : : // no need to copy attributes here, that's done by CloneFunctionInto
327 : 775 : VMap[F] = NF;
328 : : }
329 : :
330 : : // Now that all of the things that global variable initializer can refer to
331 : : // have been created, loop through and copy the global variable referrers
332 : : // over... We also set the attributes on the globals now.
333 [ + + ]: 71 : for (GlobalVariable *GV : Globals) {
334 [ + + ]: 22 : if (GV->isDeclaration())
335 : 6 : continue;
336 : :
337 : 16 : GlobalVariable *NGV = cast<GlobalVariable>(VMap[GV]);
338 [ + - ]: 16 : if (GV->hasInitializer())
339 : 16 : NGV->setInitializer(MapValue(GV->getInitializer(), VMap));
340 : :
341 : 32 : SmallVector<std::pair<unsigned, MDNode *>, 1> MDs;
342 : 16 : GV->getAllMetadata(MDs);
343 [ - + ]: 16 : for (auto MD : MDs)
344 : 0 : NGV->addMetadata(
345 : : MD.first,
346 : : #if JL_LLVM_VERSION >= 130000
347 : 0 : *MapMetadata(MD.second, VMap));
348 : : #else
349 : : *MapMetadata(MD.second, VMap, RF_MoveDistinctMDs));
350 : : #endif
351 : :
352 : 16 : copyComdat(NGV, GV);
353 : :
354 : 16 : GV->setInitializer(nullptr);
355 : : }
356 : :
357 : : // Similarly, copy over and rewrite function bodies
358 [ + + ]: 824 : for (Function *F : Functions) {
359 [ + + ]: 775 : if (F->isDeclaration())
360 : 662 : continue;
361 : :
362 : 113 : Function *NF = cast<Function>(VMap[F]);
363 : : LLVM_DEBUG(dbgs() << "Processing function " << NF->getName() << "\n");
364 : :
365 : 113 : Function::arg_iterator DestI = NF->arg_begin();
366 [ + + ]: 360 : for (Function::const_arg_iterator I = F->arg_begin(); I != F->arg_end();
367 : : ++I) {
368 : 247 : DestI->setName(I->getName());
369 : 247 : VMap[&*I] = &*DestI++;
370 : : }
371 : :
372 : 226 : SmallVector<ReturnInst *, 8> Returns; // Ignore returns cloned.
373 : 113 : CloneFunctionInto(
374 : : NF,
375 : : F,
376 : : VMap,
377 : : #if JL_LLVM_VERSION >= 130000
378 : : CloneFunctionChangeType::GlobalChanges,
379 : : #else
380 : : /*ModuleLevelChanges=*/true,
381 : : #endif
382 : : Returns,
383 : : "",
384 : : nullptr,
385 : : &TypeRemapper,
386 : : &Materializer);
387 : :
388 : : // CloneFunctionInto unconditionally copies the attributes from F to NF,
389 : : // without considering e.g. the byval attribute type.
390 : 113 : AttributeList Attrs = F->getAttributes();
391 : 113 : LLVMContext &C = F->getContext();
392 [ + + ]: 472 : for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
393 : 1077 : for (Attribute::AttrKind TypedAttr :
394 [ + + ]: 1436 : {Attribute::ByVal, Attribute::StructRet, Attribute::ByRef}) {
395 : : #if JL_LLVM_VERSION >= 140000
396 : 1077 : auto Attr = Attrs.getAttributeAtIndex(i, TypedAttr);
397 : : #else
398 : : auto Attr = Attrs.getAttribute(i, TypedAttr);
399 : : #endif
400 [ - + ]: 1077 : if (Type *Ty = Attr.getValueAsType()) {
401 : : #if JL_LLVM_VERSION >= 140000
402 : : Attrs = Attrs.replaceAttributeTypeAtIndex(
403 : 0 : C, i, TypedAttr, TypeRemapper.remapType(Ty));
404 : : #else
405 : : Attrs = Attrs.replaceAttributeType(
406 : : C, i, TypedAttr, TypeRemapper.remapType(Ty));
407 : : #endif
408 : 0 : break;
409 : : }
410 : : }
411 : : }
412 : 113 : NF->setAttributes(Attrs);
413 : :
414 [ - + ]: 113 : if (F->hasPersonalityFn())
415 : 0 : NF->setPersonalityFn(MapValue(F->getPersonalityFn(), VMap));
416 : :
417 : 113 : copyComdat(NF, F);
418 : :
419 : 113 : RemoveNoopAddrSpaceCasts(NF);
420 : 113 : F->deleteBody();
421 : : }
422 : :
423 : : // And aliases
424 [ - + ]: 49 : for (GlobalAlias *GA : Aliases) {
425 : 0 : GlobalAlias *NGA = cast<GlobalAlias>(VMap[GA]);
426 [ # # ]: 0 : if (const Constant *C = GA->getAliasee())
427 : 0 : NGA->setAliasee(MapValue(C, VMap));
428 : :
429 : 0 : GA->setAliasee(nullptr);
430 : : }
431 : :
432 : : // And named metadata
433 [ + + ]: 147 : for (auto &NMD : M.named_metadata()) {
434 [ + + ]: 294 : for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i)
435 : 196 : NMD.setOperand(i, MapMetadata(NMD.getOperand(i), VMap));
436 : : }
437 : :
438 : : // Now that we've duplicated everything, remove the old references
439 [ + + ]: 71 : for (GlobalVariable *GV : Globals)
440 : 22 : GV->eraseFromParent();
441 [ - + ]: 49 : for (GlobalAlias *GA : Aliases)
442 : 0 : GA->eraseFromParent();
443 [ + + ]: 824 : for (Function *F : Functions)
444 : 775 : F->eraseFromParent();
445 : :
446 : : // Finally, remangle calls to intrinsic
447 [ + + ]: 833 : for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE;) {
448 : 784 : Function *F = &*FI++;
449 [ + + ]: 784 : if (auto Remangled = Intrinsic::remangleIntrinsicFunction(F)) {
450 : 9 : F->replaceAllUsesWith(Remangled.getValue());
451 : 9 : F->eraseFromParent();
452 : : }
453 : : }
454 : :
455 : 49 : return true;
456 : : }
457 : :
458 : :
459 : : struct RemoveAddrspacesPassLegacy : public ModulePass {
460 : : static char ID;
461 : : AddrspaceRemapFunction ASRemapper;
462 : 49 : RemoveAddrspacesPassLegacy(
463 : : AddrspaceRemapFunction ASRemapper = removeAllAddrspaces)
464 : 49 : : ModulePass(ID), ASRemapper(ASRemapper){};
465 : :
466 : : public:
467 : 49 : bool runOnModule(Module &M) override {
468 : 49 : return removeAddrspaces(M, ASRemapper);
469 : : }
470 : : };
471 : :
472 : : char RemoveAddrspacesPassLegacy::ID = 0;
473 : : static RegisterPass<RemoveAddrspacesPassLegacy>
474 : : X("RemoveAddrspaces",
475 : : "Remove IR address space information.",
476 : : false,
477 : : false);
478 : :
479 : 0 : Pass *createRemoveAddrspacesPass(
480 : : AddrspaceRemapFunction ASRemapper = removeAllAddrspaces)
481 : : {
482 : 0 : return new RemoveAddrspacesPassLegacy(ASRemapper);
483 : : }
484 : :
485 : 0 : RemoveAddrspacesPass::RemoveAddrspacesPass() : RemoveAddrspacesPass(removeAllAddrspaces) {}
486 : :
487 : 0 : PreservedAnalyses RemoveAddrspacesPass::run(Module &M, ModuleAnalysisManager &AM) {
488 [ # # ]: 0 : if (removeAddrspaces(M, ASRemapper)) {
489 : 0 : return PreservedAnalyses::allInSet<CFGAnalyses>();
490 : : } else {
491 : 0 : return PreservedAnalyses::all();
492 : : }
493 : : }
494 : :
495 : :
496 : : //
497 : : // Julia-specific pass
498 : : //
499 : :
500 : 616 : unsigned removeJuliaAddrspaces(unsigned AS)
501 : : {
502 [ + + + - ]: 616 : if (AddressSpace::FirstSpecial <= AS && AS <= AddressSpace::LastSpecial)
503 : 220 : return AddressSpace::Generic;
504 : : else
505 : 396 : return AS;
506 : : }
507 : :
508 : : struct RemoveJuliaAddrspacesPassLegacy : public ModulePass {
509 : : static char ID;
510 : : RemoveAddrspacesPassLegacy Pass;
511 : 49 : RemoveJuliaAddrspacesPassLegacy() : ModulePass(ID), Pass(removeJuliaAddrspaces){};
512 : :
513 : 49 : bool runOnModule(Module &M) override { return Pass.runOnModule(M); }
514 : : };
515 : :
516 : : char RemoveJuliaAddrspacesPassLegacy::ID = 0;
517 : : static RegisterPass<RemoveJuliaAddrspacesPassLegacy>
518 : : Y("RemoveJuliaAddrspaces",
519 : : "Remove IR address space information.",
520 : : false,
521 : : false);
522 : :
523 : 49 : Pass *createRemoveJuliaAddrspacesPass()
524 : : {
525 : 49 : return new RemoveJuliaAddrspacesPassLegacy();
526 : : }
527 : :
528 : 0 : PreservedAnalyses RemoveJuliaAddrspacesPass::run(Module &M, ModuleAnalysisManager &AM) {
529 : 0 : return RemoveAddrspacesPass(removeJuliaAddrspaces).run(M, AM);
530 : : }
531 : :
532 : 0 : extern "C" JL_DLLEXPORT void LLVMExtraAddRemoveJuliaAddrspacesPass_impl(LLVMPassManagerRef PM)
533 : : {
534 : 0 : unwrap(PM)->add(createRemoveJuliaAddrspacesPass());
535 : 0 : }
|