llvm (一)安装并创建Module

本文详细介绍了如何在Linux系统中安装LLVM及Clang,包括默认安装、自定义安装步骤,以及如何执行测试样例(如hello.c)和创建第一个LLVM模块。教程还展示了使用clang-emit-llvm和相关工具的操作过程。

参考资料:https://zhuanlan.zhihu.com/p/450602843

一、安装并测试

默认安装:sudo apt-get install clang llvm
查看安装:clang --version && llvm-config --version
查看位置:whereis clang && whereis llvm-config

自定义安装:数字17为安装的版本【安装参考】
下载安装:wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 17
查看安装:clang-17 --version && llvm-config-17 --version
查看位置:whereis clang-17 && whereis llvm-config-17
软链接:sudo cd /usr/bin && ln -s clang-17 clang && ln -s clang++17 clang++ && ln -s llvm-config-17 llvm-config

常用命令

  • clang/clang++
    clang hello.c -o a.out
    clang -emit-llvm -S hello.c -o hello.ll

    clang++ hello.cpp -o a.out
    clang++ -emit-llvm -S hello.cpp -o hello.ll

  • llvm-as/llvm-dis
    llvm-as hello.ll -o hello.bc
    llvm-dis hello.bc -o hello.ll

  • llc/lli
    llc hello.ll -o hello.s
    lli hello.ll

  • 可以设置软链接来使用(可选)
    ln -s clang-17 clang
    ln -s clang++17 clang++
    ln -s llvm-config-17 llvm-config

二、执行测试样例

hello.c

#include <stdio.h>

int main() 
{
    int c = 1 + 2;
    printf("hello word! calculate(1+2)=%d", c);
    return 0;
}

clang -emit-llvm -S hello.c -o hello.ll

user@user:~/test01$ cat hello.ll
; ModuleID = 'hello.c'
source_filename = "hello.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@.str = private unnamed_addr constant [30 x i8] c"hello word! calculate(1+2)=%d\00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 3, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([30 x i8], [30 x i8]* @.str, i64 0, i64 0), i32 %3)
  ret i32 0
}

declare dso_local i32 @printf(i8*, ...) #1

attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 10.0.0-4ubuntu1 "}

llc hello.ll -o hello.s

wangsp@wangsp:~/test01$ cat hello.s
        .text
        .file   "hello.c"
        .globl  main                    # -- Begin function main
        .p2align        4, 0x90
        .type   main,@function
main:                                   # @main
        .cfi_startproc
# %bb.0:
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register %rbp
        subq    $16, %rsp
        movl    $0, -8(%rbp)
        movl    $3, -4(%rbp)
        movl    -4(%rbp), %esi
        movabsq $.L.str, %rdi
        movb    $0, %al
        callq   printf
        xorl    %eax, %eax
        addq    $16, %rsp
        popq    %rbp
        .cfi_def_cfa %rsp, 8
        retq
.Lfunc_end0:
        .size   main, .Lfunc_end0-main
        .cfi_endproc
                                        # -- End function
        .type   .L.str,@object          # @.str
        .section        .rodata.str1.1,"aMS",@progbits,1
.L.str:
        .asciz  "hello word! calculate(1+2)=%d"
        .size   .L.str, 30

        .ident  "clang version 10.0.0-4ubuntu1 "
        .section        ".note.GNU-stack","",@progbits

三、第一个Module

创建Module需要用到 LLVMContextModule 这两个类。
引入头文件和命名空间并创建LLVMContext和Module

#include <cstdio>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"

using namespace llvm;

static std::unique_ptr<LLVMContext> TheContext;
static std::unique_ptr<Module> TheModule;

static void InitializeModule() {
	TheContext = std::make_unique<LLVMContext>();
	TheModule = std::make_unique<Module>("first modlue", *TheContext);
}

int main(int argc, char* argv[]) {
	InitializeModule();
	TheModule->print(errs(), nullptr);
	return 0;
}
clang++ module.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -fno-rtti -o toy.out
./toy.out
; ModuleID = 'first modlue'
source_filename = "first modlue"
LLVM创建 `llvm::APFloat` 类型的常量(`ConstantFP`)需要结合 `llvm::APFloat` 和 LLVM IR 的构建接口。以下是详细步骤和示例代码: --- ### **步骤 1:创建 `llvm::APFloat` 对象** 首先,根据目标浮点格式(如 `float`、`double`)和数值初始化 `APFloat`: ```cpp #include "llvm/ADT/APFloat.h" #include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/IRBuilder.h" llvm::LLVMContext context; llvm::Module module("test", context); llvm::IRBuilder<> builder(context); // 创建 APFloat 对象(例如双精度值 3.14) llvm::APFloat apf(llvm::APFloat::IEEEdouble(), "3.14"); ``` --- ### **步骤 2:创建 `ConstantFP` 常量** 使用 `llvm::ConstantFP::get()` 将 `APFloat` 转换为 LLVM IR 常量: ```cpp // 方法 1:直接通过 Context 和 APFloat 创建 llvm::ConstantFP* constFloat = llvm::ConstantFP::get(context, apf); // 方法 2:指定类型(如 Type::getDoubleTy)和 APFloat llvm::Type* doubleTy = llvm::Type::getDoubleTy(context); llvm::ConstantFP* constFloatTyped = llvm::ConstantFP::get(doubleTy, apf); ``` --- ### **完整示例** ```cpp #include "llvm/ADT/APFloat.h" #include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/raw_ostream.h" int main() { llvm::LLVMContext context; llvm::Module module("test", context); llvm::IRBuilder<> builder(context); // 1. 创建 APFloat 常量值 llvm::APFloat pi(llvm::APFloat::IEEEdouble(), "3.1415926535"); // 2. 转换为 LLVM ConstantFP llvm::ConstantFP* constPi = llvm::ConstantFP::get(context, pi); // 3. 在 IR 中使用该常量(例如存储到全局变量) llvm::Type* doubleTy = llvm::Type::getDoubleTy(context); llvm::GlobalVariable* global = new llvm::GlobalVariable( module, doubleTy, true, llvm::GlobalValue::ExternalLinkage, constPi, "pi" ); // 验证:输出 IR module.print(llvm::outs(), nullptr); return 0; } ``` **输出 IR 示例**: ```llvm ; ModuleID = 'test' source_filename = "test" @pi = global double 3.1415926535000000, align 8 ``` --- ### **关键点说明** 1. **浮点格式匹配**: - `APFloat` 的格式(如 `IEEEdouble`)必须与目标 `Type`(如 `Type::getDoubleTy`)致,否则可能触发断言。 2. **直接通过字符串初始化**: - 推荐使用字符串(如 `"3.14"`)而非浮点字面量(如 `3.14f`),避免精度损失。 3. **特殊值处理**: - 若需表示 NaN 或 Inf,使用 `APFloat::getNaN()` 或 `APFloat::getInf()`: ```cpp llvm::APFloat nan = llvm::APFloat::getNaN(llvm::APFloat::IEEEdouble()); llvm::ConstantFP* constNaN = llvm::ConstantFP::get(context, nan); ``` 4. **性能优化**: - 频繁使用的常量可缓存为全局变量,避免重复创建。 --- ### **常见问题** 1. **如何创建 `float` 类型的常量?** 使用 `llvm::APFloat::IEEEsingle()` 和 `Type::getFloatTy`: ```cpp llvm::APFloat f(llvm::APFloat::IEEEsingle(), "1.5"); llvm::ConstantFP* constF = llvm::ConstantFP::get(llvm::Type::getFloatTy(context), f); ``` 2. **`APFloat` 和 `ConstantFP` 的区别?** - `APFloat` 是 LLVM 内部的高精度浮点表示,而 `ConstantFP` 是 LLVM IR 中的常量节点。 3. **如何从 C++ 浮点值创建 `APFloat`?** 使用 `llvm::APFloat(float)` 或 `llvm::APFloat(double)` 构造函数(注意可能丢失精度): ```cpp llvm::APFloat fval(1.25f); // 单精度 llvm::APFloat dval(3.14); // 双精度 ``` --- ### **总结** - **核心流程**:`APFloat` 初始化 → `ConstantFP::get()` → 嵌入 IR。 - **最佳实践**:优先使用字符串初始化 `APFloat`,确保精度;检查浮点格式与 IR 类型的匹配性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SongpingWang

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值