Coverage Report

Created: 2026-06-30 06:10

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