Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/lib/llvm/codegen.cpp
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
#include "llvm/codegen.h"
5
6
#include "aot/version.h"
7
#include "common/defines.h"
8
#include "common/hash.h"
9
#include "data.h"
10
#include "llvm.h"
11
12
#include <charconv>
13
#include <fstream>
14
#include <lld/Common/Driver.h>
15
#include <random>
16
#include <sstream>
17
18
#if LLVM_VERSION_MAJOR >= 14
19
#include <lld/Common/CommonLinkerContext.h>
20
#endif
21
#if LLVM_VERSION_MAJOR >= 17
22
#if WASMEDGE_OS_MACOS
23
LLD_HAS_DRIVER(macho)
24
#elif WASMEDGE_OS_LINUX
25
LLD_HAS_DRIVER(elf)
26
#elif WASMEDGE_OS_WINDOWS
27
LLD_HAS_DRIVER(coff)
28
#endif
29
#endif
30
31
#if WASMEDGE_OS_MACOS
32
#include <sys/utsname.h>
33
#include <unistd.h>
34
#endif
35
#if WASMEDGE_OS_WINDOWS
36
#include <llvm/Object/COFF.h>
37
#endif
38
39
#if WASMEDGE_OS_LINUX
40
90.8k
#define SYMBOL(X) X
41
#elif WASMEDGE_OS_MACOS
42
#define SYMBOL(X) "_" X
43
#elif WASMEDGE_OS_WINDOWS
44
#define SYMBOL(X) X
45
#endif
46
47
namespace LLVM = WasmEdge::LLVM;
48
using namespace std::literals;
49
50
namespace {
51
52
using namespace WasmEdge;
53
54
#if WASMEDGE_OS_MACOS
55
// Get current OS version
56
std::string getOSVersion() noexcept {
57
  struct utsname Info;
58
  if (::uname(&Info)) {
59
    // default os version
60
    return "13.0.0"s;
61
  }
62
  std::string_view Release = Info.release;
63
  auto GetNum = [](std::string_view &String) noexcept {
64
    uint64_t Result = 0;
65
    while (!String.empty() && std::isdigit(String[0])) {
66
      Result = Result * 10 + (String[0] - '0');
67
      String = String.substr(1);
68
    }
69
    return Result;
70
  };
71
  auto SkipDot = [](std::string_view &String) noexcept {
72
    if (!String.empty() && String[0] == '.')
73
      String = String.substr(1);
74
  };
75
  uint64_t Major = GetNum(Release);
76
  SkipDot(Release);
77
  uint64_t Minor = GetNum(Release);
78
  SkipDot(Release);
79
  uint64_t Micro = GetNum(Release);
80
81
  if (Major == 0) {
82
    Major = 8;
83
  }
84
  if (Major <= 19) {
85
    Micro = 0;
86
    Minor = Major - 4;
87
    Major = 10;
88
  } else {
89
    Micro = 0;
90
    Minor = 0;
91
    Major = 11 + Major - 20;
92
  }
93
94
  return fmt::format("{}.{}.{}"sv, Major, Minor, Micro);
95
}
96
// Get current SDK version
97
std::string getSDKVersion() noexcept {
98
  // TODO: parse SDKSettings.json to get real version
99
  return "12.1"s;
100
}
101
// Get current SDK version in pair
102
std::pair<uint32_t, uint32_t> getSDKVersionPair() noexcept {
103
  // TODO: parse SDKSettings.json to get real version
104
  return {UINT32_C(12), UINT32_C(1)};
105
}
106
#endif
107
108
3.57M
Expect<void> WriteByte(std::ostream &OS, uint8_t Data) noexcept {
109
3.57M
  OS.put(static_cast<char>(Data));
110
3.57M
  return {};
111
3.57M
}
112
113
18.9k
Expect<void> WriteU32(std::ostream &OS, uint32_t Data) noexcept {
114
23.8k
  do {
115
23.8k
    uint8_t Byte = static_cast<uint8_t>(Data & UINT32_C(0x7f));
116
23.8k
    Data >>= 7;
117
23.8k
    if (Data > UINT32_C(0)) {
118
4.87k
      Byte |= UINT8_C(0x80);
119
4.87k
    }
120
23.8k
    WriteByte(OS, Byte);
121
23.8k
  } while (Data > UINT32_C(0));
122
18.9k
  return {};
123
18.9k
}
124
125
45.3k
Expect<void> WriteU64(std::ostream &OS, uint64_t Data) noexcept {
126
81.4k
  do {
127
81.4k
    uint8_t Byte = static_cast<uint8_t>(Data & UINT64_C(0x7f));
128
81.4k
    Data >>= 7;
129
81.4k
    if (Data > UINT64_C(0)) {
130
36.0k
      Byte |= UINT8_C(0x80);
131
36.0k
    }
132
81.4k
    WriteByte(OS, Byte);
133
81.4k
  } while (Data > UINT64_C(0));
134
45.3k
  return {};
135
45.3k
}
136
137
14.6k
Expect<void> WriteName(std::ostream &OS, std::string_view Data) noexcept {
138
14.6k
  WriteU32(OS, static_cast<uint32_t>(Data.size()));
139
3.44M
  for (const auto C : Data) {
140
3.44M
    WriteByte(OS, static_cast<uint8_t>(C));
141
3.44M
  }
142
14.6k
  return {};
143
14.6k
}
144
145
inline constexpr bool startsWith(std::string_view Value,
146
32.0k
                                 std::string_view Prefix) noexcept {
147
32.0k
  return Value.size() >= Prefix.size() &&
148
32.0k
         Value.substr(0, Prefix.size()) == Prefix;
149
32.0k
}
150
151
4.28k
std::filesystem::path uniquePath(const std::filesystem::path Model) noexcept {
152
4.28k
  using size_type = std::filesystem::path::string_type::size_type;
153
4.28k
  using value_type = std::filesystem::path::value_type;
154
4.28k
  static const auto Hex = "0123456789abcdef"sv;
155
4.28k
  std::uniform_int_distribution<size_type> Distribution(0, Hex.size() - 1);
156
4.28k
  auto String = Model.native();
157
124k
  for (size_type N = String.size(), I = 0; I < N; ++I) {
158
120k
    if (String[I] == static_cast<value_type>('%')) {
159
42.8k
      String[I] = static_cast<value_type>(Hex[Distribution(Hash::RandEngine)]);
160
42.8k
    }
161
120k
  }
162
4.28k
  return String;
163
4.28k
}
164
165
4.28k
std::filesystem::path createTemp(const std::filesystem::path Model) noexcept {
166
4.28k
  while (true) {
167
4.28k
    auto Result = uniquePath(Model);
168
4.28k
    std::error_code Error;
169
4.28k
    if (!std::filesystem::exists(Result, Error)) {
170
4.28k
      if (Error) {
171
0
        return {};
172
0
      }
173
4.28k
      return Result;
174
4.28k
    }
175
4.28k
  }
176
4.28k
}
177
178
// Write output object and link
179
Expect<void> outputNativeLibrary(const std::filesystem::path &OutputPath,
180
2.14k
                                 const LLVM::MemoryBuffer &OSVec) noexcept {
181
2.14k
  spdlog::info("output start"sv);
182
2.14k
  std::filesystem::path ObjectName;
183
2.14k
  {
184
    // tempfile
185
2.14k
    std::filesystem::path OPath(OutputPath);
186
#if WASMEDGE_OS_WINDOWS
187
    OPath.replace_extension("%%%%%%%%%%.obj"sv);
188
#else
189
2.14k
    OPath.replace_extension("%%%%%%%%%%.o"sv);
190
2.14k
#endif
191
2.14k
    ObjectName = createTemp(OPath);
192
2.14k
    if (ObjectName.empty()) {
193
      // TODO:return error
194
0
      spdlog::error("so file creation failed:{}"sv, OPath.u8string());
195
0
      return Unexpect(ErrCode::Value::IllegalPath);
196
0
    }
197
2.14k
    std::ofstream OS(ObjectName, std::ios_base::binary);
198
2.14k
    OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size()));
199
2.14k
    OS.close();
200
2.14k
  }
201
202
  // link
203
0
  bool LinkResult = false;
204
#if WASMEDGE_OS_MACOS
205
  const auto OSVersion = getOSVersion();
206
  const auto SDKVersion = getSDKVersion();
207
#if LLVM_VERSION_MAJOR >= 14
208
  // LLVM 14 replaces the older mach_o lld implementation with the new one.
209
  // So we need to change the namespace after LLVM 14.x released.
210
  // Reference: https://reviews.llvm.org/D114842
211
  LinkResult = lld::macho::link(
212
#else
213
  LinkResult = lld::mach_o::link(
214
#endif
215
      std::initializer_list<const char *>{
216
          "lld", "-arch",
217
#if defined(__x86_64__)
218
          "x86_64",
219
#elif defined(__aarch64__)
220
          "arm64",
221
#else
222
#error Unsupported architecture on the MacOS!
223
#endif
224
#if LLVM_VERSION_MAJOR >= 14
225
          // LLVM 14 replaces the older mach_o lld implementation with the new
226
          // one. And it require -arch and -platform_version to always be
227
          // specified. Reference: https://reviews.llvm.org/D97799
228
          "-platform_version", "macos", OSVersion.c_str(), SDKVersion.c_str(),
229
#else
230
          "-sdk_version", SDKVersion.c_str(),
231
#endif
232
          "-dylib", "-demangle", "-macosx_version_min", OSVersion.c_str(),
233
          "-syslibroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk",
234
          ObjectName.u8string().c_str(), "-o", OutputPath.u8string().c_str()},
235
#elif WASMEDGE_OS_LINUX
236
  LinkResult = lld::elf::link(
237
2.14k
      std::initializer_list<const char *>{"ld.lld", "--eh-frame-hdr",
238
2.14k
                                          "--shared", "--gc-sections",
239
2.14k
                                          "--discard-all", ObjectName.c_str(),
240
2.14k
                                          "-o", OutputPath.u8string().c_str()},
241
#elif WASMEDGE_OS_WINDOWS
242
  LinkResult = lld::coff::link(
243
      std::initializer_list<const char *>{
244
          "lld-link", "-dll", "-base:0", "-nologo",
245
          ObjectName.u8string().c_str(),
246
          ("-out:" + OutputPath.u8string()).c_str()},
247
#endif
248
249
#if LLVM_VERSION_MAJOR >= 14
250
      llvm::outs(), llvm::errs(), false, false
251
#elif LLVM_VERSION_MAJOR >= 10
252
      false, llvm::outs(), llvm::errs()
253
#else
254
      false, llvm::errs()
255
#endif
256
2.14k
  );
257
258
#if LLVM_VERSION_MAJOR >= 14
259
  lld::CommonLinkerContext::destroy();
260
#endif
261
262
2.14k
  if (LinkResult) {
263
2.14k
    std::error_code Error;
264
2.14k
    std::filesystem::remove(ObjectName, Error);
265
#if WASMEDGE_OS_WINDOWS
266
    std::filesystem::path LibPath(OutputPath);
267
    LibPath.replace_extension(".lib"sv);
268
    std::filesystem::remove(LibPath, Error);
269
#endif
270
271
2.14k
    spdlog::info("codegen done"sv);
272
2.14k
  } else {
273
0
    spdlog::error("link error"sv);
274
0
  }
275
276
#if WASMEDGE_OS_MACOS
277
  // codesign
278
  if (LinkResult) {
279
    pid_t PID = ::fork();
280
    if (PID == -1) {
281
      spdlog::error("codesign error on fork:{}"sv, std::strerror(errno));
282
    } else if (PID == 0) {
283
      execlp("/usr/bin/codesign", "codesign", "-s", "-",
284
             OutputPath.u8string().c_str(), nullptr);
285
      std::exit(256);
286
    } else {
287
      int ChildStat;
288
      waitpid(PID, &ChildStat, 0);
289
      if (const int Status = WEXITSTATUS(ChildStat); Status != 0) {
290
        spdlog::error("codesign exited with status {}"sv, Status);
291
      }
292
    }
293
  }
294
#endif
295
296
2.14k
  return {};
297
2.14k
}
298
299
Expect<void> outputWasmLibrary(LLVM::Context LLContext,
300
                               const std::filesystem::path &OutputPath,
301
                               Span<const Byte> Data,
302
2.14k
                               const LLVM::MemoryBuffer &OSVec) noexcept {
303
2.14k
  std::filesystem::path SharedObjectName;
304
2.14k
  {
305
    // tempfile
306
2.14k
    std::filesystem::path SOPath(OutputPath);
307
2.14k
    SOPath.replace_extension("%%%%%%%%%%" WASMEDGE_LIB_EXTENSION);
308
2.14k
    SharedObjectName = createTemp(SOPath);
309
2.14k
    if (SharedObjectName.empty()) {
310
      // TODO:return error
311
0
      spdlog::error("so file creation failed:{}"sv, SOPath.u8string());
312
0
      return Unexpect(ErrCode::Value::IllegalPath);
313
0
    }
314
2.14k
    std::ofstream OS(SharedObjectName, std::ios_base::binary);
315
2.14k
    OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size()));
316
2.14k
    OS.close();
317
2.14k
  }
318
319
2.14k
  EXPECTED_TRY(outputNativeLibrary(SharedObjectName, OSVec));
320
321
2.14k
  LLVM::MemoryBuffer SOFile;
322
2.14k
  if (auto [Res, ErrorMessage] =
323
2.14k
          LLVM::MemoryBuffer::getFile(SharedObjectName.u8string().c_str());
324
2.14k
      unlikely(ErrorMessage)) {
325
0
    spdlog::error("object file open error:{}"sv, ErrorMessage.string_view());
326
0
    return Unexpect(ErrCode::Value::IllegalPath);
327
2.14k
  } else {
328
2.14k
    SOFile = std::move(Res);
329
2.14k
  }
330
331
2.14k
  LLVM::Binary ObjFile;
332
2.14k
  if (auto [Res, ErrorMessage] = LLVM::Binary::create(SOFile, LLContext);
333
2.14k
      unlikely(ErrorMessage)) {
334
0
    spdlog::error("object file parse error:{}"sv, ErrorMessage.string_view());
335
0
    return Unexpect(ErrCode::Value::IllegalPath);
336
2.14k
  } else {
337
2.14k
    ObjFile = std::move(Res);
338
2.14k
  }
339
340
2.14k
  std::string OSCustomSecVec;
341
2.14k
  {
342
2.14k
    std::ostringstream OS;
343
2.14k
    WriteName(OS, "wasmedge"sv);
344
2.14k
    WriteU32(OS, AOT::kBinaryVersion);
345
346
2.14k
#if WASMEDGE_OS_LINUX
347
2.14k
    WriteByte(OS, UINT8_C(1));
348
#elif WASMEDGE_OS_MACOS
349
    WriteByte(OS, UINT8_C(2));
350
#elif WASMEDGE_OS_WINDOWS
351
    WriteByte(OS, UINT8_C(3));
352
#else
353
#error Unsupported operating system!
354
#endif
355
356
2.14k
#if defined(__x86_64__)
357
2.14k
    WriteByte(OS, UINT8_C(1));
358
#elif defined(__aarch64__)
359
    WriteByte(OS, UINT8_C(2));
360
#elif defined(__riscv) && __riscv_xlen == 64
361
    WriteByte(OS, UINT8_C(3));
362
#elif defined(__arm__) && __ARM_ARCH == 7
363
    WriteByte(OS, UINT8_C(4));
364
#else
365
#error Unsupported hardware architecture!
366
#endif
367
368
2.14k
    std::vector<std::pair<std::string, uint64_t>> SymbolTable;
369
2.14k
#if !WASMEDGE_OS_WINDOWS
370
2.14k
    for (auto Symbol = ObjFile.symbols();
371
24.6k
         Symbol && !ObjFile.isSymbolEnd(Symbol); Symbol.next()) {
372
22.4k
      SymbolTable.emplace_back(Symbol.getName(), Symbol.getAddress());
373
22.4k
    }
374
#else
375
    for (auto &Symbol :
376
         llvm::object::unwrap<llvm::object::COFFObjectFile>(ObjFile.unwrap())
377
             ->export_directories()) {
378
      llvm::StringRef Name;
379
      if (auto Error = Symbol.getSymbolName(Name); unlikely(!!Error)) {
380
        continue;
381
      } else if (Name.empty()) {
382
        continue;
383
      }
384
      uint32_t Offset = 0;
385
      if (auto Error = Symbol.getExportRVA(Offset); unlikely(!!Error)) {
386
        continue;
387
      }
388
      SymbolTable.emplace_back(Name.str(), Offset);
389
    }
390
#endif
391
2.14k
    uint64_t VersionAddress = 0, IntrinsicsAddress = 0;
392
2.14k
    std::vector<uint64_t> Types;
393
2.14k
    std::vector<uint64_t> Codes;
394
2.14k
    uint64_t CodesMin = std::numeric_limits<uint64_t>::max();
395
22.4k
    for (const auto &[Name, Address] : SymbolTable) {
396
22.4k
      if (Name == SYMBOL("version"sv)) {
397
2.14k
        VersionAddress = Address;
398
20.3k
      } else if (Name == SYMBOL("intrinsics"sv)) {
399
2.14k
        IntrinsicsAddress = Address;
400
18.1k
      } else if (startsWith(Name, SYMBOL("t"sv))) {
401
4.32k
        uint64_t Index = 0;
402
4.32k
        std::from_chars(Name.data() + SYMBOL("t"sv).size(),
403
4.32k
                        Name.data() + Name.size(), Index);
404
4.32k
        if (Types.size() < Index + 1) {
405
3.92k
          Types.resize(Index + 1);
406
3.92k
        }
407
4.32k
        Types[Index] = Address;
408
13.8k
      } else if (startsWith(Name, SYMBOL("f"sv))) {
409
11.7k
        uint64_t Index = 0;
410
11.7k
        std::from_chars(Name.data() + SYMBOL("f"sv).size(),
411
11.7k
                        Name.data() + Name.size(), Index);
412
11.7k
        if (Codes.size() < Index + 1) {
413
9.65k
          Codes.resize(Index + 1);
414
9.65k
        }
415
11.7k
        CodesMin = std::min(CodesMin, Index);
416
11.7k
        Codes[Index] = Address;
417
11.7k
      }
418
22.4k
    }
419
2.14k
    if (CodesMin != std::numeric_limits<uint64_t>::max()) {
420
1.95k
      Codes.erase(Codes.begin(),
421
1.95k
                  Codes.begin() + static_cast<int64_t>(CodesMin));
422
1.95k
    }
423
2.14k
    WriteU64(OS, VersionAddress);
424
2.14k
    WriteU64(OS, IntrinsicsAddress);
425
2.14k
    WriteU64(OS, Types.size());
426
4.32k
    for (const uint64_t TypeAddress : Types) {
427
4.32k
      WriteU64(OS, TypeAddress);
428
4.32k
    }
429
2.14k
    WriteU64(OS, Codes.size());
430
11.7k
    for (const uint64_t CodeAddress : Codes) {
431
11.7k
      WriteU64(OS, CodeAddress);
432
11.7k
    }
433
434
2.14k
    uint32_t SectionCount = 0;
435
33.9k
    for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section);
436
31.8k
         Section.next()) {
437
31.8k
      if (Section.getSize() == 0) {
438
2.14k
        continue;
439
2.14k
      }
440
29.6k
      if (!Section.isEHFrame() && !Section.isPData() && !Section.isText() &&
441
29.6k
          !Section.isData() && !Section.isBSS()) {
442
19.2k
        continue;
443
19.2k
      }
444
10.3k
      ++SectionCount;
445
10.3k
    }
446
2.14k
    WriteU32(OS, SectionCount);
447
448
33.9k
    for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section);
449
31.8k
         Section.next()) {
450
31.8k
      if (Section.getSize() == 0) {
451
2.14k
        continue;
452
2.14k
      }
453
29.6k
      std::vector<char> Content;
454
29.6k
      if (auto Res = Section.getContents(); unlikely(Res.empty())) {
455
0
        assumingUnreachable();
456
29.6k
      } else {
457
29.6k
        Content.assign(Res.begin(), Res.end());
458
29.6k
      }
459
29.6k
      if (Section.isEHFrame() || Section.isPData()) {
460
2.02k
        WriteByte(OS, UINT8_C(4));
461
27.6k
      } else if (Section.isText()) {
462
2.02k
        WriteByte(OS, UINT8_C(1));
463
25.6k
      } else if (Section.isData()) {
464
4.17k
        WriteByte(OS, UINT8_C(2));
465
21.4k
      } else if (Section.isBSS()) {
466
2.14k
        WriteByte(OS, UINT8_C(3));
467
19.2k
      } else {
468
19.2k
        continue;
469
19.2k
      }
470
471
10.3k
      WriteU64(OS, Section.getAddress());
472
10.3k
      WriteU64(OS, Content.size());
473
10.3k
      WriteName(OS, std::string_view(Content.data(), Content.size()));
474
10.3k
    }
475
2.14k
    OSCustomSecVec = OS.str();
476
2.14k
  }
477
478
0
  spdlog::info("output start"sv);
479
480
2.14k
  std::ofstream OS(OutputPath, std::ios_base::binary);
481
2.14k
  if (!OS) {
482
0
    spdlog::error("output failed."sv);
483
0
    return Unexpect(ErrCode::Value::IllegalPath);
484
0
  }
485
2.14k
  OS.write(reinterpret_cast<const char *>(Data.data()),
486
2.14k
           static_cast<std::streamsize>(Data.size()));
487
  // Custom section id
488
2.14k
  WriteByte(OS, UINT8_C(0x00));
489
2.14k
  WriteName(OS, std::string_view(OSCustomSecVec.data(), OSCustomSecVec.size()));
490
491
2.14k
  std::error_code Error;
492
2.14k
  std::filesystem::remove(SharedObjectName, Error);
493
494
2.14k
  spdlog::info("output done"sv);
495
2.14k
  return {};
496
2.14k
}
497
498
} // namespace
499
500
namespace WasmEdge::LLVM {
501
502
Expect<void> CodeGen::codegen(Span<const Byte> WasmData, Data D,
503
2.14k
                              std::filesystem::path OutputPath) noexcept {
504
2.14k
  auto LLContext = D.extract().LLContext();
505
2.14k
  auto &LLModule = D.extract().LLModule;
506
2.14k
  auto &TM = D.extract().TM;
507
2.14k
  std::filesystem::path LLPath(OutputPath);
508
2.14k
  LLPath.replace_extension("ll"sv);
509
510
#if WASMEDGE_OS_WINDOWS
511
  {
512
    // create dummy dllmain function
513
    auto FTy = LLVM::Type::getFunctionType(LLContext.getInt32Ty(), {});
514
    auto F =
515
        LLModule.addFunction(FTy, LLVMExternalLinkage, "_DllMainCRTStartup");
516
    F.setVisibility(LLVMProtectedVisibility);
517
    F.setDSOLocal(true);
518
    F.addFnAttr(
519
        LLVM::Attribute::createString(LLContext, "no-stack-arg-probe"sv, {}));
520
    F.addFnAttr(
521
        LLVM::Attribute::createEnum(LLContext, LLVM::Core::StrictFP, 0));
522
    F.addFnAttr(LLVM::Attribute::createEnum(LLContext, LLVM::Core::UWTable,
523
                                            LLVM::Core::UWTableDefault));
524
    F.addFnAttr(
525
        LLVM::Attribute::createEnum(LLContext, LLVM::Core::NoReturn, 0));
526
    LLVM::Builder Builder(LLContext);
527
    Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F, "entry"));
528
    Builder.createRet(LLContext.getInt32(1u));
529
530
    auto A = LLModule.addAlias(F.getType(), F, "_fltused");
531
    A.setLinkage(LLVMExternalLinkage);
532
    A.setVisibility(LLVMProtectedVisibility);
533
    A.setDSOLocal(true);
534
  }
535
#endif
536
#if WASMEDGE_OS_MACOS
537
  {
538
    const auto [Major, Minor] = getSDKVersionPair();
539
    LLModule.addFlag(LLVMModuleFlagBehaviorError, "SDK Version"sv,
540
                     LLVM::Value::getConstVector32(LLContext, {Major, Minor}));
541
  }
542
#endif
543
544
2.14k
  if (Conf.getCompilerConfigure().getOutputFormat() !=
545
2.14k
      CompilerConfigure::OutputFormat::Wasm) {
546
    // create wasm.code and wasm.size
547
0
    auto Int32Ty = LLContext.getInt32Ty();
548
0
    auto Content = LLVM::Value::getConstString(
549
0
        LLContext,
550
0
        {reinterpret_cast<const char *>(WasmData.data()), WasmData.size()},
551
0
        true);
552
0
    LLModule.addGlobal(Content.getType(), true, LLVMExternalLinkage, Content,
553
0
                       "wasm.code");
554
0
    LLModule.addGlobal(Int32Ty, true, LLVMExternalLinkage,
555
0
                       LLVM::Value::getConstInt(Int32Ty, WasmData.size()),
556
0
                       "wasm.size");
557
0
    for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) {
558
0
      if (Fn.getLinkage() == LLVMInternalLinkage) {
559
0
        Fn.setLinkage(LLVMExternalLinkage);
560
0
        Fn.setVisibility(LLVMProtectedVisibility);
561
0
        Fn.setDSOLocal(true);
562
0
        Fn.setDLLStorageClass(LLVMDLLExportStorageClass);
563
0
      }
564
0
    }
565
2.14k
  } else {
566
20.1k
    for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) {
567
17.9k
      if (Fn.getLinkage() == LLVMInternalLinkage) {
568
27
        Fn.setLinkage(LLVMPrivateLinkage);
569
27
        Fn.setDSOLocal(true);
570
27
        Fn.setDLLStorageClass(LLVMDefaultStorageClass);
571
27
      }
572
17.9k
    }
573
2.14k
  }
574
575
  // set dllexport
576
6.43k
  for (auto GV = LLModule.getFirstGlobal(); GV; GV = GV.getNextGlobal()) {
577
4.29k
    if (GV.getLinkage() == LLVMExternalLinkage) {
578
4.28k
      GV.setVisibility(LLVMProtectedVisibility);
579
4.28k
      GV.setDSOLocal(true);
580
4.28k
      GV.setDLLStorageClass(LLVMDLLExportStorageClass);
581
4.28k
    }
582
4.29k
  }
583
584
2.14k
  if (Conf.getCompilerConfigure().isDumpIR()) {
585
0
    if (auto ErrorMessage = LLModule.printModuleToFile("wasm.ll");
586
0
        unlikely(ErrorMessage)) {
587
0
      spdlog::error("wasm.ll open error:{}"sv, ErrorMessage.string_view());
588
0
      return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath);
589
0
    }
590
0
  }
591
592
2.14k
  spdlog::info("codegen start"sv);
593
  // codegen
594
2.14k
  {
595
2.14k
    if (Conf.getCompilerConfigure().isDumpIR()) {
596
0
      if (auto ErrorMessage = LLModule.printModuleToFile("wasm-opt.ll")) {
597
        // TODO:return error
598
0
        spdlog::error("printModuleToFile failed"sv);
599
0
        return Unexpect(ErrCode::Value::IllegalPath);
600
0
      }
601
0
    }
602
603
2.14k
    auto [OSVec, ErrorMessage] =
604
2.14k
        TM.emitToMemoryBuffer(LLModule, LLVMObjectFile);
605
2.14k
    if (ErrorMessage) {
606
      // TODO:return error
607
0
      spdlog::error("addPassesToEmitFile failed"sv);
608
0
      return Unexpect(ErrCode::Value::IllegalPath);
609
0
    }
610
611
2.14k
    if (Conf.getCompilerConfigure().getOutputFormat() ==
612
2.14k
        CompilerConfigure::OutputFormat::Wasm) {
613
2.14k
      EXPECTED_TRY(outputWasmLibrary(LLContext, OutputPath, WasmData, OSVec));
614
2.14k
    } else {
615
0
      EXPECTED_TRY(outputNativeLibrary(OutputPath, OSVec));
616
0
    }
617
2.14k
  }
618
619
2.14k
  return {};
620
2.14k
}
621
622
} // namespace WasmEdge::LLVM