Coverage Report

Created: 2026-09-28 06:22

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