Coverage Report

Created: 2026-11-09 06:49

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
86.8k
#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.59M
Expect<void> WriteByte(std::ostream &OS, uint8_t Data) noexcept {
114
3.59M
  OS.put(static_cast<char>(Data));
115
3.59M
  return {};
116
3.59M
}
117
118
20.0k
Expect<void> WriteU32(std::ostream &OS, uint32_t Data) noexcept {
119
24.5k
  do {
120
24.5k
    uint8_t Byte = static_cast<uint8_t>(Data & UINT32_C(0x7f));
121
24.5k
    Data >>= 7;
122
24.5k
    if (Data > UINT32_C(0)) {
123
4.50k
      Byte |= UINT8_C(0x80);
124
4.50k
    }
125
24.5k
    WriteByte(OS, Byte);
126
24.5k
  } while (Data > UINT32_C(0));
127
20.0k
  return {};
128
20.0k
}
129
130
46.1k
Expect<void> WriteU64(std::ostream &OS, uint64_t Data) noexcept {
131
81.6k
  do {
132
81.6k
    uint8_t Byte = static_cast<uint8_t>(Data & UINT64_C(0x7f));
133
81.6k
    Data >>= 7;
134
81.6k
    if (Data > UINT64_C(0)) {
135
35.5k
      Byte |= UINT8_C(0x80);
136
35.5k
    }
137
81.6k
    WriteByte(OS, Byte);
138
81.6k
  } while (Data > UINT64_C(0));
139
46.1k
  return {};
140
46.1k
}
141
142
15.5k
Expect<void> WriteName(std::ostream &OS, std::string_view Data) noexcept {
143
15.5k
  WriteU32(OS, static_cast<uint32_t>(Data.size()));
144
3.46M
  for (const auto C : Data) {
145
3.46M
    WriteByte(OS, static_cast<uint8_t>(C));
146
3.46M
  }
147
15.5k
  return {};
148
15.5k
}
149
150
inline constexpr bool startsWith(std::string_view Value,
151
30.0k
                                 std::string_view Prefix) noexcept {
152
30.0k
  return Value.size() >= Prefix.size() &&
153
30.0k
         Value.substr(0, Prefix.size()) == Prefix;
154
30.0k
}
155
156
4.55k
std::filesystem::path uniquePath(const std::filesystem::path Model) noexcept {
157
4.55k
  using size_type = std::filesystem::path::string_type::size_type;
158
4.55k
  using value_type = std::filesystem::path::value_type;
159
4.55k
  static const auto Hex = "0123456789abcdef"sv;
160
4.55k
  std::uniform_int_distribution<size_type> Distribution(0, Hex.size() - 1);
161
4.55k
  auto String = Model.native();
162
132k
  for (size_type N = String.size(), I = 0; I < N; ++I) {
163
127k
    if (String[I] == static_cast<value_type>('%')) {
164
45.5k
      String[I] = static_cast<value_type>(Hex[Distribution(Hash::RandEngine)]);
165
45.5k
    }
166
127k
  }
167
4.55k
  return String;
168
4.55k
}
169
170
4.55k
std::filesystem::path createTemp(const std::filesystem::path Model) noexcept {
171
4.55k
  while (true) {
172
4.55k
    auto Result = uniquePath(Model);
173
4.55k
    std::error_code Error;
174
4.55k
    if (!std::filesystem::exists(Result, Error)) {
175
4.55k
      if (Error) {
176
0
        return {};
177
0
      }
178
4.55k
      return Result;
179
4.55k
    }
180
4.55k
  }
181
4.55k
}
182
183
// Write output object and link
184
Expect<void> outputNativeLibrary(const std::filesystem::path &OutputPath,
185
2.27k
                                 const LLVM::MemoryBuffer &OSVec) noexcept {
186
2.27k
  spdlog::info("output start"sv);
187
2.27k
  std::filesystem::path ObjectName;
188
2.27k
  {
189
    // tempfile
190
2.27k
    std::filesystem::path OPath(OutputPath);
191
#if WASMEDGE_OS_WINDOWS
192
    OPath.replace_extension("%%%%%%%%%%.obj"sv);
193
#else
194
2.27k
    OPath.replace_extension("%%%%%%%%%%.o"sv);
195
2.27k
#endif
196
2.27k
    ObjectName = createTemp(OPath);
197
2.27k
    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.27k
    std::ofstream OS(ObjectName, std::ios_base::binary);
203
2.27k
    OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size()));
204
2.27k
    OS.close();
205
2.27k
  }
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.27k
  std::lock_guard<std::mutex> Lock(LldMutex);
212
2.27k
  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.27k
      std::initializer_list<const char *>{"ld.lld", "--eh-frame-hdr",
247
2.27k
                                          "--shared", "--gc-sections",
248
2.27k
                                          "--discard-all", ObjectName.c_str(),
249
2.27k
                                          "-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.27k
  );
266
267
2.27k
#if LLVM_VERSION_MAJOR < 14
268
#else
269
  lld::CommonLinkerContext::destroy();
270
#endif
271
272
2.27k
  if (LinkResult) {
273
2.27k
    std::error_code Error;
274
2.27k
    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.27k
    spdlog::info("codegen done"sv);
282
2.27k
  } 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.27k
  return {};
307
2.27k
}
308
309
Expect<void> outputWasmLibrary(LLVM::Context LLContext,
310
                               const std::filesystem::path &OutputPath,
311
                               Span<const Byte> Data,
312
2.27k
                               const LLVM::MemoryBuffer &OSVec) noexcept {
313
2.27k
  std::filesystem::path SharedObjectName;
314
2.27k
  {
315
    // tempfile
316
2.27k
    std::filesystem::path SOPath(OutputPath);
317
2.27k
    SOPath.replace_extension("%%%%%%%%%%" WASMEDGE_LIB_EXTENSION);
318
2.27k
    SharedObjectName = createTemp(SOPath);
319
2.27k
    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.27k
    std::ofstream OS(SharedObjectName, std::ios_base::binary);
325
2.27k
    OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size()));
326
2.27k
    OS.close();
327
2.27k
  }
328
329
2.27k
  EXPECTED_TRY(outputNativeLibrary(SharedObjectName, OSVec));
330
331
2.27k
  LLVM::MemoryBuffer SOFile;
332
2.27k
  if (auto [Res, ErrorMessage] =
333
2.27k
          LLVM::MemoryBuffer::getFile(u8string(SharedObjectName).c_str());
334
2.27k
      unlikely(ErrorMessage)) {
335
0
    spdlog::error("object file open error:{}"sv, ErrorMessage.string_view());
336
0
    return Unexpect(ErrCode::Value::IllegalPath);
337
2.27k
  } else {
338
2.27k
    SOFile = std::move(Res);
339
2.27k
  }
340
341
2.27k
  LLVM::Binary ObjFile;
342
2.27k
  if (auto [Res, ErrorMessage] = LLVM::Binary::create(SOFile, LLContext);
343
2.27k
      unlikely(ErrorMessage)) {
344
0
    spdlog::error("object file parse error:{}"sv, ErrorMessage.string_view());
345
0
    return Unexpect(ErrCode::Value::IllegalPath);
346
2.27k
  } else {
347
2.27k
    ObjFile = std::move(Res);
348
2.27k
  }
349
350
2.27k
  std::string OSCustomSecVec;
351
2.27k
  {
352
2.27k
    std::ostringstream OS;
353
2.27k
    WriteName(OS, "wasmedge"sv);
354
2.27k
    WriteU32(OS, AOT::kBinaryVersion);
355
356
2.27k
#if WASMEDGE_OS_LINUX
357
2.27k
    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.27k
#if defined(__x86_64__)
367
2.27k
    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.27k
    std::vector<std::pair<std::string, uint64_t>> SymbolTable;
381
2.27k
#if !WASMEDGE_OS_WINDOWS
382
2.27k
    for (auto Symbol = ObjFile.symbols();
383
24.2k
         Symbol && !ObjFile.isSymbolEnd(Symbol); Symbol.next()) {
384
21.9k
      SymbolTable.emplace_back(Symbol.getName(), Symbol.getAddress());
385
21.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.27k
    uint64_t VersionAddress = 0, IntrinsicsAddress = 0;
404
2.27k
    std::vector<uint64_t> Types;
405
2.27k
    std::vector<uint64_t> Codes;
406
2.27k
    uint64_t CodesMin = std::numeric_limits<uint64_t>::max();
407
21.9k
    for (const auto &[Name, Address] : SymbolTable) {
408
21.9k
      if (Name == SYMBOL("version"sv)) {
409
2.27k
        VersionAddress = Address;
410
19.7k
      } else if (Name == SYMBOL("intrinsics"sv)) {
411
2.27k
        IntrinsicsAddress = Address;
412
17.4k
      } else if (startsWith(Name, SYMBOL("t"sv))) {
413
4.84k
        uint64_t Index = 0;
414
4.84k
        std::from_chars(Name.data() + SYMBOL("t"sv).size(),
415
4.84k
                        Name.data() + Name.size(), Index);
416
4.84k
        if (Types.size() < Index + 1) {
417
4.42k
          Types.resize(Index + 1);
418
4.42k
        }
419
4.84k
        Types[Index] = Address;
420
12.5k
      } else if (startsWith(Name, SYMBOL("f"sv))) {
421
10.3k
        uint64_t Index = 0;
422
10.3k
        std::from_chars(Name.data() + SYMBOL("f"sv).size(),
423
10.3k
                        Name.data() + Name.size(), Index);
424
10.3k
        if (Codes.size() < Index + 1) {
425
8.46k
          Codes.resize(Index + 1);
426
8.46k
        }
427
10.3k
        CodesMin = std::min(CodesMin, Index);
428
10.3k
        Codes[Index] = Address;
429
10.3k
      }
430
21.9k
    }
431
2.27k
    if (CodesMin != std::numeric_limits<uint64_t>::max()) {
432
2.00k
      Codes.erase(Codes.begin(),
433
2.00k
                  Codes.begin() + static_cast<int64_t>(CodesMin));
434
2.00k
    }
435
2.27k
    WriteU64(OS, VersionAddress);
436
2.27k
    WriteU64(OS, IntrinsicsAddress);
437
2.27k
    WriteU64(OS, Types.size());
438
4.84k
    for (const uint64_t TypeAddress : Types) {
439
4.84k
      WriteU64(OS, TypeAddress);
440
4.84k
    }
441
2.27k
    WriteU64(OS, Codes.size());
442
10.3k
    for (const uint64_t CodeAddress : Codes) {
443
10.3k
      WriteU64(OS, CodeAddress);
444
10.3k
    }
445
446
2.27k
    uint32_t SectionCount = 0;
447
36.0k
    for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section);
448
33.7k
         Section.next()) {
449
33.7k
      if (Section.getSize() == 0) {
450
2.27k
        continue;
451
2.27k
      }
452
31.4k
      if (!Section.isEHFrame() && !Section.isPData() && !Section.isText() &&
453
27.1k
          !Section.isData() && !Section.isBSS()) {
454
20.5k
        continue;
455
20.5k
      }
456
10.9k
      ++SectionCount;
457
10.9k
    }
458
2.27k
    WriteU32(OS, SectionCount);
459
460
36.0k
    for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section);
461
33.7k
         Section.next()) {
462
33.7k
      if (Section.getSize() == 0) {
463
2.27k
        continue;
464
2.27k
      }
465
31.4k
      std::vector<char> Content(Section.getSize());
466
31.4k
      if (!Section.isVirtual()) {
467
29.1k
        if (auto Res = Section.getContents(); unlikely(Res.empty())) {
468
0
          assumingUnreachable();
469
29.1k
        } else {
470
29.1k
          Content.assign(Res.begin(), Res.end());
471
29.1k
        }
472
29.1k
      }
473
31.4k
      if (Section.isEHFrame() || Section.isPData()) {
474
2.13k
        WriteByte(OS, UINT8_C(4));
475
29.3k
      } else if (Section.isText()) {
476
2.13k
        WriteByte(OS, UINT8_C(1));
477
27.1k
      } else if (Section.isData()) {
478
4.41k
        WriteByte(OS, UINT8_C(2));
479
22.7k
      } else if (Section.isBSS()) {
480
2.27k
        WriteByte(OS, UINT8_C(3));
481
20.5k
      } else {
482
20.5k
        continue;
483
20.5k
      }
484
485
10.9k
      WriteU64(OS, Section.getAddress());
486
10.9k
      WriteU64(OS, Content.size());
487
10.9k
      WriteName(OS, std::string_view(Content.data(), Content.size()));
488
10.9k
    }
489
2.27k
    OSCustomSecVec = OS.str();
490
2.27k
  }
491
492
0
  spdlog::info("output start"sv);
493
494
2.27k
  std::ofstream OS(OutputPath, std::ios_base::binary);
495
2.27k
  if (!OS) {
496
0
    spdlog::error("output failed."sv);
497
0
    return Unexpect(ErrCode::Value::IllegalPath);
498
0
  }
499
2.27k
  OS.write(reinterpret_cast<const char *>(Data.data()),
500
2.27k
           static_cast<std::streamsize>(Data.size()));
501
  // Custom section id
502
2.27k
  WriteByte(OS, UINT8_C(0x00));
503
2.27k
  WriteName(OS, std::string_view(OSCustomSecVec.data(), OSCustomSecVec.size()));
504
505
2.27k
  std::error_code Error;
506
2.27k
  std::filesystem::remove(SharedObjectName, Error);
507
508
2.27k
  spdlog::info("output done"sv);
509
2.27k
  return {};
510
2.27k
}
511
512
} // namespace
513
514
namespace WasmEdge::LLVM {
515
516
Expect<void> CodeGen::codegen(Span<const Byte> WasmData, Data D,
517
2.27k
                              std::filesystem::path OutputPath) noexcept {
518
  // CompileFromBuffer skips the loader, so reject empty path here.
519
2.27k
  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.27k
  auto LLContext = D.extract().getLLContext();
525
2.27k
  auto &LLModule = D.extract().LLModule;
526
2.27k
  auto &TM = D.extract().TM;
527
2.27k
  std::filesystem::path LLPath(OutputPath);
528
2.27k
  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.27k
  if (Conf.getCompilerConfigure().getOutputFormat() !=
565
2.27k
      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.27k
  } else {
586
21.1k
    for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) {
587
18.8k
      if (Fn.getLinkage() == LLVMInternalLinkage) {
588
41
        Fn.setLinkage(LLVMPrivateLinkage);
589
41
        Fn.setDSOLocal(true);
590
41
        Fn.setDLLStorageClass(LLVMDefaultStorageClass);
591
41
      }
592
18.8k
    }
593
2.27k
  }
594
595
  // set dllexport
596
6.84k
  for (auto GV = LLModule.getFirstGlobal(); GV; GV = GV.getNextGlobal()) {
597
4.56k
    if (GV.getLinkage() == LLVMExternalLinkage) {
598
4.55k
      GV.setVisibility(LLVMProtectedVisibility);
599
4.55k
      GV.setDSOLocal(true);
600
4.55k
      GV.setDLLStorageClass(LLVMDLLExportStorageClass);
601
4.55k
    }
602
4.56k
  }
603
604
2.27k
  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.27k
  spdlog::info("codegen start"sv);
613
  // codegen
614
2.27k
  {
615
2.27k
    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.27k
    auto [OSVec, ErrorMessage] =
624
2.27k
        TM.emitToMemoryBuffer(LLModule, LLVMObjectFile);
625
2.27k
    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.27k
    if (Conf.getCompilerConfigure().getOutputFormat() ==
632
2.27k
        CompilerConfigure::OutputFormat::Wasm) {
633
2.27k
      EXPECTED_TRY(outputWasmLibrary(LLContext, OutputPath, WasmData, OSVec));
634
2.27k
    } else {
635
0
      EXPECTED_TRY(outputNativeLibrary(OutputPath, OSVec));
636
0
    }
637
2.27k
  }
638
639
2.27k
  return {};
640
2.27k
}
641
642
} // namespace WasmEdge::LLVM