Coverage Report

Created: 2025-08-29 06:29

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