Coverage Report

Created: 2026-11-12 06:35

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