Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
///
9
/// \file
10
/// This file defines the WebAssembly-specific subclass of TargetMachine.
11
///
12
//===----------------------------------------------------------------------===//
13
14
#include "WebAssemblyTargetMachine.h"
15
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16
#include "TargetInfo/WebAssemblyTargetInfo.h"
17
#include "WebAssembly.h"
18
#include "WebAssemblyMachineFunctionInfo.h"
19
#include "WebAssemblyTargetObjectFile.h"
20
#include "WebAssemblyTargetTransformInfo.h"
21
#include "llvm/CodeGen/MIRParser/MIParser.h"
22
#include "llvm/CodeGen/MachineFunctionPass.h"
23
#include "llvm/CodeGen/Passes.h"
24
#include "llvm/CodeGen/RegAllocRegistry.h"
25
#include "llvm/CodeGen/TargetPassConfig.h"
26
#include "llvm/IR/Function.h"
27
#include "llvm/Support/TargetRegistry.h"
28
#include "llvm/Target/TargetOptions.h"
29
#include "llvm/Transforms/Scalar.h"
30
#include "llvm/Transforms/Scalar/LowerAtomic.h"
31
#include "llvm/Transforms/Utils.h"
32
using namespace llvm;
33
34
#define DEBUG_TYPE "wasm"
35
36
// Emscripten's asm.js-style exception handling
37
static cl::opt<bool> EnableEmException(
38
    "enable-emscripten-cxx-exceptions",
39
    cl::desc("WebAssembly Emscripten-style exception handling"),
40
    cl::init(false));
41
42
// Emscripten's asm.js-style setjmp/longjmp handling
43
static cl::opt<bool> EnableEmSjLj(
44
    "enable-emscripten-sjlj",
45
    cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
46
    cl::init(false));
47
48
139k
extern "C" void LLVMInitializeWebAssemblyTarget() {
49
139k
  // Register the target.
50
139k
  RegisterTargetMachine<WebAssemblyTargetMachine> X(
51
139k
      getTheWebAssemblyTarget32());
52
139k
  RegisterTargetMachine<WebAssemblyTargetMachine> Y(
53
139k
      getTheWebAssemblyTarget64());
54
139k
55
139k
  // Register backend passes
56
139k
  auto &PR = *PassRegistry::getPassRegistry();
57
139k
  initializeWebAssemblyAddMissingPrototypesPass(PR);
58
139k
  initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
59
139k
  initializeLowerGlobalDtorsPass(PR);
60
139k
  initializeFixFunctionBitcastsPass(PR);
61
139k
  initializeOptimizeReturnedPass(PR);
62
139k
  initializeWebAssemblyArgumentMovePass(PR);
63
139k
  initializeWebAssemblySetP2AlignOperandsPass(PR);
64
139k
  initializeWebAssemblyReplacePhysRegsPass(PR);
65
139k
  initializeWebAssemblyPrepareForLiveIntervalsPass(PR);
66
139k
  initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
67
139k
  initializeWebAssemblyMemIntrinsicResultsPass(PR);
68
139k
  initializeWebAssemblyRegStackifyPass(PR);
69
139k
  initializeWebAssemblyRegColoringPass(PR);
70
139k
  initializeWebAssemblyFixIrreducibleControlFlowPass(PR);
71
139k
  initializeWebAssemblyLateEHPreparePass(PR);
72
139k
  initializeWebAssemblyExceptionInfoPass(PR);
73
139k
  initializeWebAssemblyCFGSortPass(PR);
74
139k
  initializeWebAssemblyCFGStackifyPass(PR);
75
139k
  initializeWebAssemblyExplicitLocalsPass(PR);
76
139k
  initializeWebAssemblyLowerBrUnlessPass(PR);
77
139k
  initializeWebAssemblyRegNumberingPass(PR);
78
139k
  initializeWebAssemblyPeepholePass(PR);
79
139k
  initializeWebAssemblyCallIndirectFixupPass(PR);
80
139k
}
81
82
//===----------------------------------------------------------------------===//
83
// WebAssembly Lowering public interface.
84
//===----------------------------------------------------------------------===//
85
86
static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM,
87
484
                                           const Triple &TT) {
88
484
  if (!RM.hasValue()) {
89
407
    // Default to static relocation model.  This should always be more optimial
90
407
    // than PIC since the static linker can determine all global addresses and
91
407
    // assume direct function calls.
92
407
    return Reloc::Static;
93
407
  }
94
77
95
77
  if (!TT.isOSEmscripten()) {
96
69
    // Relocation modes other than static are currently implemented in a way
97
69
    // that only works for Emscripten, so disable them if we aren't targeting
98
69
    // Emscripten.
99
69
    return Reloc::Static;
100
69
  }
101
8
102
8
  return *RM;
103
8
}
104
105
/// Create an WebAssembly architecture model.
106
///
107
WebAssemblyTargetMachine::WebAssemblyTargetMachine(
108
    const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
109
    const TargetOptions &Options, Optional<Reloc::Model> RM,
110
    Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT)
111
    : LLVMTargetMachine(T,
112
                        TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128"
113
                                         : "e-m:e-p:32:32-i64:64-n32:64-S128",
114
                        TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT),
115
                        getEffectiveCodeModel(CM, CodeModel::Large), OL),
116
484
      TLOF(new WebAssemblyTargetObjectFile()) {
117
484
  // WebAssembly type-checks instructions, but a noreturn function with a return
118
484
  // type that doesn't match the context will cause a check failure. So we lower
119
484
  // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
120
484
  // 'unreachable' instructions which is meant for that case.
121
484
  this->Options.TrapUnreachable = true;
122
484
123
484
  // WebAssembly treats each function as an independent unit. Force
124
484
  // -ffunction-sections, effectively, so that we can emit them independently.
125
484
  this->Options.FunctionSections = true;
126
484
  this->Options.DataSections = true;
127
484
  this->Options.UniqueSectionNames = true;
128
484
129
484
  initAsmInfo();
130
484
131
484
  // Note that we don't use setRequiresStructuredCFG(true). It disables
132
484
  // optimizations than we're ok with, and want, such as critical edge
133
484
  // splitting and tail merging.
134
484
}
135
136
471
WebAssemblyTargetMachine::~WebAssemblyTargetMachine() = default; // anchor.
137
138
const WebAssemblySubtarget *
139
WebAssemblyTargetMachine::getSubtargetImpl(std::string CPU,
140
88.5k
                                           std::string FS) const {
141
88.5k
  auto &I = SubtargetMap[CPU + FS];
142
88.5k
  if (!I) {
143
546
    I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this);
144
546
  }
145
88.5k
  return I.get();
146
88.5k
}
147
148
const WebAssemblySubtarget *
149
88.1k
WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
150
88.1k
  Attribute CPUAttr = F.getFnAttribute("target-cpu");
151
88.1k
  Attribute FSAttr = F.getFnAttribute("target-features");
152
88.1k
153
88.1k
  std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
154
88.1k
                        ? 
CPUAttr.getValueAsString().str()36
155
88.1k
                        : 
TargetCPU88.0k
;
156
88.1k
  std::string FS = !FSAttr.hasAttribute(Attribute::None)
157
88.1k
                       ? 
FSAttr.getValueAsString().str()83.9k
158
88.1k
                       : 
TargetFS4.20k
;
159
88.1k
160
88.1k
  // This needs to be done before we create a new subtarget since any
161
88.1k
  // creation will depend on the TM and the code generation flags on the
162
88.1k
  // function that reside in TargetOptions.
163
88.1k
  resetTargetOptions(F);
164
88.1k
165
88.1k
  return getSubtargetImpl(CPU, FS);
166
88.1k
}
167
168
namespace {
169
170
class CoalesceFeaturesAndStripAtomics final : public ModulePass {
171
  // Take the union of all features used in the module and use it for each
172
  // function individually, since having multiple feature sets in one module
173
  // currently does not make sense for WebAssembly. If atomics are not enabled,
174
  // also strip atomic operations and thread local storage.
175
  static char ID;
176
  WebAssemblyTargetMachine *WasmTM;
177
178
public:
179
  CoalesceFeaturesAndStripAtomics(WebAssemblyTargetMachine *WasmTM)
180
426
      : ModulePass(ID), WasmTM(WasmTM) {}
181
182
426
  bool runOnModule(Module &M) override {
183
426
    FeatureBitset Features = coalesceFeatures(M);
184
426
185
426
    std::string FeatureStr = getFeatureString(Features);
186
426
    for (auto &F : M)
187
5.17k
      replaceFeatures(F, FeatureStr);
188
426
189
426
    bool StrippedAtomics = false;
190
426
    bool StrippedTLS = false;
191
426
192
426
    if (!Features[WebAssembly::FeatureAtomics])
193
409
      StrippedAtomics = stripAtomics(M);
194
426
195
426
    if (!Features[WebAssembly::FeatureBulkMemory])
196
412
      StrippedTLS = stripThreadLocals(M);
197
426
198
426
    if (StrippedAtomics && 
!StrippedTLS6
)
199
6
      stripThreadLocals(M);
200
420
    else if (StrippedTLS && 
!StrippedAtomics3
)
201
3
      stripAtomics(M);
202
426
203
426
    recordFeatures(M, Features, StrippedAtomics || 
StrippedTLS421
);
204
426
205
426
    // Conservatively assume we have made some change
206
426
    return true;
207
426
  }
208
209
private:
210
426
  FeatureBitset coalesceFeatures(const Module &M) {
211
426
    FeatureBitset Features =
212
426
        WasmTM
213
426
            ->getSubtargetImpl(WasmTM->getTargetCPU(),
214
426
                               WasmTM->getTargetFeatureString())
215
426
            ->getFeatureBits();
216
426
    for (auto &F : M)
217
5.17k
      Features |= WasmTM->getSubtargetImpl(F)->getFeatureBits();
218
426
    return Features;
219
426
  }
220
221
426
  std::string getFeatureString(const FeatureBitset &Features) {
222
426
    std::string Ret;
223
4.26k
    for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
224
4.26k
      if (Features[KV.Value])
225
138
        Ret += (StringRef("+") + KV.Key + ",").str();
226
4.26k
    }
227
426
    return Ret;
228
426
  }
229
230
5.17k
  void replaceFeatures(Function &F, const std::string &Features) {
231
5.17k
    F.removeFnAttr("target-features");
232
5.17k
    F.removeFnAttr("target-cpu");
233
5.17k
    F.addFnAttr("target-features", Features);
234
5.17k
  }
235
236
412
  bool stripAtomics(Module &M) {
237
412
    // Detect whether any atomics will be lowered, since there is no way to tell
238
412
    // whether the LowerAtomic pass lowers e.g. stores.
239
412
    bool Stripped = false;
240
4.55k
    for (auto &F : M) {
241
4.55k
      for (auto &B : F) {
242
11.0k
        for (auto &I : B) {
243
11.0k
          if (I.isAtomic()) {
244
6
            Stripped = true;
245
6
            goto done;
246
6
          }
247
11.0k
        }
248
4.49k
      }
249
4.55k
    }
250
412
251
413
  done:
252
413
    if (!Stripped)
253
407
      return false;
254
6
255
6
    LowerAtomicPass Lowerer;
256
6
    FunctionAnalysisManager FAM;
257
6
    for (auto &F : M)
258
279
      Lowerer.run(F, FAM);
259
6
260
6
    return true;
261
6
  }
262
263
418
  bool stripThreadLocals(Module &M) {
264
418
    bool Stripped = false;
265
418
    for (auto &GV : M.globals()) {
266
324
      if (GV.getThreadLocalMode() !=
267
324
          GlobalValue::ThreadLocalMode::NotThreadLocal) {
268
3
        Stripped = true;
269
3
        GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal);
270
3
      }
271
324
    }
272
418
    return Stripped;
273
418
  }
274
275
427
  void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) {
276
4.26k
    for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
277
4.26k
      std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
278
4.26k
      if (KV.Value == WebAssembly::FeatureAtomics && 
Stripped427
) {
279
9
        // "atomics" is special: code compiled without atomics may have had its
280
9
        // atomics lowered to nonatomic operations. In that case, atomics is
281
9
        // disallowed to prevent unsafe linking with atomics-enabled objects.
282
9
        assert(!Features[WebAssembly::FeatureAtomics] ||
283
9
               !Features[WebAssembly::FeatureBulkMemory]);
284
9
        M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
285
9
                        wasm::WASM_FEATURE_PREFIX_DISALLOWED);
286
4.26k
      } else if (Features[KV.Value]) {
287
138
        // Otherwise features are marked Used or not mentioned
288
138
        M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
289
138
                        wasm::WASM_FEATURE_PREFIX_USED);
290
138
      }
291
4.26k
    }
292
427
  }
293
};
294
char CoalesceFeaturesAndStripAtomics::ID = 0;
295
296
/// WebAssembly Code Generator Pass Configuration Options.
297
class WebAssemblyPassConfig final : public TargetPassConfig {
298
public:
299
  WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM)
300
453
      : TargetPassConfig(TM, PM) {}
301
302
852
  WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const {
303
852
    return getTM<WebAssemblyTargetMachine>();
304
852
  }
305
306
  FunctionPass *createTargetRegisterAllocator(bool) override;
307
308
  void addIRPasses() override;
309
  bool addInstSelector() override;
310
  void addPostRegAlloc() override;
311
426
  bool addGCPasses() override { return false; }
312
  void addPreEmitPass() override;
313
314
  // No reg alloc
315
13
  bool addRegAssignmentFast() override { return false; }
316
317
  // No reg alloc
318
413
  bool addRegAssignmentOptimized() override { return false; }
319
};
320
} // end anonymous namespace
321
322
TargetTransformInfo
323
33.7k
WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) {
324
33.7k
  return TargetTransformInfo(WebAssemblyTTIImpl(this, F));
325
33.7k
}
326
327
TargetPassConfig *
328
453
WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) {
329
453
  return new WebAssemblyPassConfig(*this, PM);
330
453
}
331
332
0
FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
333
0
  return nullptr; // No reg alloc
334
0
}
335
336
//===----------------------------------------------------------------------===//
337
// The following functions are called from lib/CodeGen/Passes.cpp to modify
338
// the CodeGen pass sequence.
339
//===----------------------------------------------------------------------===//
340
341
426
void WebAssemblyPassConfig::addIRPasses() {
342
426
  // Runs LowerAtomicPass if necessary
343
426
  addPass(new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine()));
344
426
345
426
  // This is a no-op if atomics are not used in the module
346
426
  addPass(createAtomicExpandPass());
347
426
348
426
  // Add signatures to prototype-less function declarations
349
426
  addPass(createWebAssemblyAddMissingPrototypes());
350
426
351
426
  // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
352
426
  addPass(createWebAssemblyLowerGlobalDtors());
353
426
354
426
  // Fix function bitcasts, as WebAssembly requires caller and callee signatures
355
426
  // to match.
356
426
  addPass(createWebAssemblyFixFunctionBitcasts());
357
426
358
426
  // Optimize "returned" function attributes.
359
426
  if (getOptLevel() != CodeGenOpt::None)
360
413
    addPass(createWebAssemblyOptimizeReturned());
361
426
362
426
  // If exception handling is not enabled and setjmp/longjmp handling is
363
426
  // enabled, we lower invokes into calls and delete unreachable landingpad
364
426
  // blocks. Lowering invokes when there is no EH support is done in
365
426
  // TargetPassConfig::addPassesToHandleExceptions, but this runs after this
366
426
  // function and SjLj handling expects all invokes to be lowered before.
367
426
  if (!EnableEmException &&
368
426
      
TM->Options.ExceptionModel == ExceptionHandling::None423
) {
369
409
    addPass(createLowerInvokePass());
370
409
    // The lower invoke pass may create unreachable code. Remove it in order not
371
409
    // to process dead blocks in setjmp/longjmp handling.
372
409
    addPass(createUnreachableBlockEliminationPass());
373
409
  }
374
426
375
426
  // Handle exceptions and setjmp/longjmp if enabled.
376
426
  if (EnableEmException || 
EnableEmSjLj423
)
377
4
    addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException,
378
4
                                                   EnableEmSjLj));
379
426
380
426
  // Expand indirectbr instructions to switches.
381
426
  addPass(createIndirectBrExpandPass());
382
426
383
426
  TargetPassConfig::addIRPasses();
384
426
}
385
386
426
bool WebAssemblyPassConfig::addInstSelector() {
387
426
  (void)TargetPassConfig::addInstSelector();
388
426
  addPass(
389
426
      createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel()));
390
426
  // Run the argument-move pass immediately after the ScheduleDAG scheduler
391
426
  // so that we can fix up the ARGUMENT instructions before anything else
392
426
  // sees them in the wrong place.
393
426
  addPass(createWebAssemblyArgumentMove());
394
426
  // Set the p2align operands. This information is present during ISel, however
395
426
  // it's inconvenient to collect. Collect it now, and update the immediate
396
426
  // operands.
397
426
  addPass(createWebAssemblySetP2AlignOperands());
398
426
  return false;
399
426
}
400
401
426
void WebAssemblyPassConfig::addPostRegAlloc() {
402
426
  // TODO: The following CodeGen passes don't currently support code containing
403
426
  // virtual registers. Consider removing their restrictions and re-enabling
404
426
  // them.
405
426
406
426
  // These functions all require the NoVRegs property.
407
426
  disablePass(&MachineCopyPropagationID);
408
426
  disablePass(&PostRAMachineSinkingID);
409
426
  disablePass(&PostRASchedulerID);
410
426
  disablePass(&FuncletLayoutID);
411
426
  disablePass(&StackMapLivenessID);
412
426
  disablePass(&LiveDebugValuesID);
413
426
  disablePass(&PatchableFunctionID);
414
426
  disablePass(&ShrinkWrapID);
415
426
416
426
  // This pass hurts code size for wasm because it can generate irreducible
417
426
  // control flow.
418
426
  disablePass(&MachineBlockPlacementID);
419
426
420
426
  TargetPassConfig::addPostRegAlloc();
421
426
}
422
423
426
void WebAssemblyPassConfig::addPreEmitPass() {
424
426
  TargetPassConfig::addPreEmitPass();
425
426
426
426
  // Rewrite pseudo call_indirect instructions as real instructions.
427
426
  // This needs to run before register stackification, because we change the
428
426
  // order of the arguments.
429
426
  addPass(createWebAssemblyCallIndirectFixup());
430
426
431
426
  // Eliminate multiple-entry loops.
432
426
  addPass(createWebAssemblyFixIrreducibleControlFlow());
433
426
434
426
  // Do various transformations for exception handling.
435
426
  // Every CFG-changing optimizations should come before this.
436
426
  addPass(createWebAssemblyLateEHPrepare());
437
426
438
426
  // Now that we have a prologue and epilogue and all frame indices are
439
426
  // rewritten, eliminate SP and FP. This allows them to be stackified,
440
426
  // colored, and numbered with the rest of the registers.
441
426
  addPass(createWebAssemblyReplacePhysRegs());
442
426
443
426
  // Preparations and optimizations related to register stackification.
444
426
  if (getOptLevel() != CodeGenOpt::None) {
445
413
    // LiveIntervals isn't commonly run this late. Re-establish preconditions.
446
413
    addPass(createWebAssemblyPrepareForLiveIntervals());
447
413
448
413
    // Depend on LiveIntervals and perform some optimizations on it.
449
413
    addPass(createWebAssemblyOptimizeLiveIntervals());
450
413
451
413
    // Prepare memory intrinsic calls for register stackifying.
452
413
    addPass(createWebAssemblyMemIntrinsicResults());
453
413
454
413
    // Mark registers as representing wasm's value stack. This is a key
455
413
    // code-compression technique in WebAssembly. We run this pass (and
456
413
    // MemIntrinsicResults above) very late, so that it sees as much code as
457
413
    // possible, including code emitted by PEI and expanded by late tail
458
413
    // duplication.
459
413
    addPass(createWebAssemblyRegStackify());
460
413
461
413
    // Run the register coloring pass to reduce the total number of registers.
462
413
    // This runs after stackification so that it doesn't consider registers
463
413
    // that become stackified.
464
413
    addPass(createWebAssemblyRegColoring());
465
413
  }
466
426
467
426
  // Sort the blocks of the CFG into topological order, a prerequisite for
468
426
  // BLOCK and LOOP markers.
469
426
  addPass(createWebAssemblyCFGSort());
470
426
471
426
  // Insert BLOCK and LOOP markers.
472
426
  addPass(createWebAssemblyCFGStackify());
473
426
474
426
  // Insert explicit local.get and local.set operators.
475
426
  addPass(createWebAssemblyExplicitLocals());
476
426
477
426
  // Lower br_unless into br_if.
478
426
  addPass(createWebAssemblyLowerBrUnless());
479
426
480
426
  // Perform the very last peephole optimizations on the code.
481
426
  if (getOptLevel() != CodeGenOpt::None)
482
413
    addPass(createWebAssemblyPeephole());
483
426
484
426
  // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
485
426
  addPass(createWebAssemblyRegNumbering());
486
426
}
487
488
yaml::MachineFunctionInfo *
489
23
WebAssemblyTargetMachine::createDefaultFuncInfoYAML() const {
490
23
  return new yaml::WebAssemblyFunctionInfo();
491
23
}
492
493
yaml::MachineFunctionInfo *WebAssemblyTargetMachine::convertFuncInfoToYAML(
494
20
    const MachineFunction &MF) const {
495
20
  const auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
496
20
  return new yaml::WebAssemblyFunctionInfo(*MFI);
497
20
}
498
499
bool WebAssemblyTargetMachine::parseMachineFunctionInfo(
500
    const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS,
501
21
    SMDiagnostic &Error, SMRange &SourceRange) const {
502
21
  const auto &YamlMFI =
503
21
      reinterpret_cast<const yaml::WebAssemblyFunctionInfo &>(MFI);
504
21
  MachineFunction &MF = PFS.MF;
505
21
  MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(YamlMFI);
506
21
  return false;
507
21
}