【译】LLVM 的设计

死代码删除(DCE,Dead Code Elimination)和激进的死代码删除(ADCE,Aggressive DCE) DCE和ADCE算法 阅读详情

LLVM 是开源的编译工具链项目,用 C++ 编写,包含一系列模块化的编译器组件和工具链,用于开发编译器前端和后端。

内容来源: https://aosabook.org/en/llvm.html
原文标题:LLVM
作者:Chris Lattner
译者:流左沙
注:翻译较原文会有一定的精简、重排和添删,主要是为了提取重要内容以达到更好的理解,请以原文为准。

Classical Compiler Design

Implications of this Design

The most important win of this classical design comes when a compiler decides to support multiple source languages or target architectures. If the compiler uses a common code representation in its optimizer, then a front end can be written for any language that can compile to it, and a back end can be written for any target that can compile from it

传统的编译器实现方式在面对支持不同的语言或架构时败下阵来。如果编译器在优化器中使用一种通用的代码表示,那么编译器前端可以用任何代码编写,后端可以写出为任何架构。

With this design, porting the compiler to support a new source language (e.g., Algol or BASIC) requires implementing a new front end, but the existing optimizer and back end can be reused.

支持一门新的编程语言只需要实现新的前端即可,但是已存在的优化器和后端都可以复用。

LLVM IR

With the historical background and context out of the way, let's dive into LLVM: The most important aspect of its design is the LLVM Intermediate Representation (IR), which is the form it uses to represent code in the compiler.

最重要的部分是 LLVM IR,编译器用它来作代码表示。

LLVM IR is a low-level RISC-like virtual instruction set. Like a real RISC instruction set, it supports linear sequences of simple instructions like add, subtract, compare, and branch. These instructions are in three address form, which means that they take some number of inputs and produce a result in a different register. LLVM IR supports labels and generally looks like a weird form of assembly language.

LLVM IR 是低层级的虚拟指令集。像真实的 RISC 指令集,它支持简单的线性指令,如加、减、比较、分支跳转。这些指令以三地址码组织,表示从一系列的输入中输出不同的结果到寄存器中。LLVM IR 支持标签以及看起来像是汇编语言。

Unlike most RISC instruction sets, LLVM is strongly typed with a simple type system (e.g., i32 is a 32-bit integer, i32** is a pointer to pointer to 32-bit integer) and some details of the machine are abstracted away. For example, the calling convention is abstracted through call and ret instructions and explicit arguments. Another significant difference from machine code is that the LLVM IR doesn't use a fixed set of named registers, it uses an infinite set of temporaries named with a % character.

不像 RISC 指令集,LLVM 使用简单的类型系统以及一些机器相关的细节被抽象化了。另一个重大区别是 LLVM IR 的机器码不使用命名的寄存器,它使用无限的临时字符名字。

Target Description Files

The "mix and match" approach allows target authors to choose what makes sense for their architecture and permits a large amount of code reuse across different targets. This brings up another challenge: each shared component needs to be able to reason about target specific properties in a generic way. For example, a shared register allocator needs to know the register file of each target and the constraints that exist between instructions and their register operands. LLVM's solution to this is for each target to provide a target description in a declarative domain-specific language (a set of .td files) processed by the tblgen tool.

混合匹配的方式可以让我们选择架构,以及让大量的代码可以在不同的目标复用。但这带来了另一大难题:每个共享模块需要有适当的方式去合理地处理目标特定属性。比如一个共享的寄存器分配器需要去知晓每个目标的寄存器文件,以及存在于不同指令之间和他们的寄存器操作数的限制。LLVM 的解决方法是对于每个目标提供一个目标描述的 dsl 文件(由 tblgen 工具去处理)。

The different subsystems supported by the .td files allow target authors to build up the different pieces of their target. For example, the x86 back end defines a register class that holds all of its 32-bit registers named "GR32" (in the .td files, target specific definitions are all caps) like this:

.td 文件支持不同子系统的构建目标,比如,x86 后端定义了一个寄存器类来保存 32 位寄存器

def GR32 : RegisterClass<[i32], 32,
  [EAX, ECX, EDX, ESI, EDI, EBX, EBP, ESP,
   R8D, R9D, R10D, R11D, R14D, R15D, R12D, R13D]> { … }

This definition says that registers in this class can hold 32-bit integer values ("i32"), prefer to be 32-bit aligned, have the specified 16 registers (which are defined elsewhere in the .td files) and have some more information to specify preferred allocation order and other things. Given this definition, specific instructions can refer to this, using it as an operand.

这个定义描述的是寄存器存有 32 位的值,且 32 位对齐,有指定的 16 个寄存器和更多的一些信息。有了这个定义,指定的指令指向它,用它作为操作数。

For example, the "complement a 32-bit register" instruction is defined as:

比如,一个 32 位寄存器指令如下

let Constraints = "$src = $dst" in
def NOT32r : I<0xF7, MRM2r,
               (outs GR32:$dst), (ins GR32:$src),
               "not{l}\t$dst",
               [(set GR32:$dst, (not GR32:$src))]>;

This definition says that NOT32r is an instruction (it uses the I tblgen class), specifies encoding information (0xF7, MRM2r), specifies that it defines an "output" 32-bit register $dst and has a 32-bit register "input" named $src (the GR32 register class defined above defines which registers are valid for the operand), specifies the assembly syntax for the instruction (using the {} syntax to handle both AT&T and Intel syntax), specifies the effect of the instruction and provides the pattern that it should match on the last line. The "let" constraint on the first line tells the register allocator that the input and output register must be allocated to the same physical register.

这个定义描述的是 NOT32r 是一条指令(使用 I 这个 tblgen 的类),指定了编码信息(0xF7, MRM2r),指明它定义了一个 32 位的输出寄存器 $dst 和有一个 32 位寄存器的输入 $src (上面定义 GR32 寄存器类可以使用了),同时指明了汇编指令的语法(使用 {} 语法去处理不同平台的语法),指明了指令的作用以及最后一行提供匹配模式。第一行的 let 语法限制让寄存器分配器要把输入和输出都分配到同一个物理寄存器上。

This definition is a very dense description of the instruction, and the common LLVM code can do a lot with information derived from it (by the tblgen tool). This one definition is enough for instruction selection to form this instruction by pattern matching on the input IR code for the compiler. It also tells the register allocator how to process it, is enough to encode and decode the instruction to machine code bytes, and is enough to parse and print the instruction in a textual form. These capabilities allow the x86 target to support generating a stand-alone x86 assembler (which is a drop-in replacement for the "gas" GNU assembler) and disassemblers from the target description as well as handle encoding the instruction for the JIT.

这个定义是对于指令的详细描述,通用的 LLVM 代码可以从这个描述中做很多事情。这些定义对于指令选择去匹配构造输入 IR 代码是足够的。同时它也能告诉寄存器分配器如何去处理它,让分配器足以去编码和解码指令到机器代码字节,以及足以以文本格式去解析和输出指令。这个能力让 x86 的目标可以支持 x86 汇编的生成,以及反汇编器也是如此,还有对于 JIT 的指令编码。

While we aim to get as much target information as possible into the .td files in a nice declarative form, we still don't have everything. Instead, we require target authors to write some C++ code for various support routines and to implement any target specific passes they might need (like X86FloatingPoint.cpp, which handles the x87 floating point stack). As LLVM continues to grow new targets, it becomes more and more important to increase the amount of the target that can be expressed in the .td file, and we continue to increase the expressiveness of the .td files to handle this. A great benefit is that it gets easier and easier write targets in LLVM as time goes on.

当我们想要把更多目标信息放到 .td 文件里,我们需要作者去写 c++ 代码去支持常规的操作,以及去实现特定平台的 pass 来处理。当 LLVM 继续添加新的目标,对于能在 .td 文件添加大量的描述变得越来越重要,之后我们会持续去增加 .td 文件的描述性去处理。一个好处就是更容易去编写 LLVM 的目标。

Choosing When and Where Each Phase Runs

As mentioned earlier, LLVM IR can be efficiently (de)serialized to/from a binary format known as LLVM bitcode. Since LLVM IR is self-contained, and serialization is a lossless process, we can do part of compilation, save our progress to disk, then continue work at some point in the future. This feature provides a number of interesting capabilities including support for link-time and install-time optimization, both of which delay code generation from "compile time".

像前面提到的,LLVM IR 会高效地去序列化或反序列化二进制格式,也就是 LLVM bitcode。由于 LLVM IR 是自举的,以及序列化是轻量的操作,我们可以进行部分的编译,保存进度到磁盘,以后再恢复执行。这个特性提供了大量有趣的功能,包括支持链接时和安装时的优化,这两个都会在编译时推迟代码的生成。

Link-Time Optimization (LTO) addresses the problem where the compiler traditionally only sees one translation unit (e.g., a .c file with all its headers) at a time and therefore cannot do optimizations (like inlining) across file boundaries. LLVM compilers like Clang support this with the -flto or -O4 command line option. This option instructs the compiler to emit LLVM bitcode to the .ofile instead of writing out a native object file, and delays code generation to link time.

LTO 指出了问题:编译器一次只能看到一个编译单元,因此没法跨文件范围做优化(如内联)。LLVM 的编译器比如 clang 支持 -flto 或者 -O4 命令。这个命令让编译器输出 bitcode 格式的 .o 文件而不是本地的目标文件,推迟代码生成到链接时。

Details differ depending on which operating system you're on, but the important bit is that the linker detects that it has LLVM bitcode in the .o files instead of native object files. When it sees this, it reads all the bitcode files into memory, links them together, then runs the LLVM optimizer over the aggregate. Since the optimizer can now see across a much larger portion of the code, it can inline, propagate constants, do more aggressive dead code elimination, and more across file boundaries. While many modern compilers support LTO, most of them (e.g., GCC, Open64, the Intel compiler, etc.) do so by having an expensive and slow serialization process. In LLVM, LTO falls out naturally from the design of the system, and works across different source languages (unlike many other compilers) because the IR is truly source language neutral.

具体细节会因操作系统而异,但链接器重要的一点是检查 .o 文件是 bitcode 格式还是本地目标格式。当看到是 bitcode 格式,它会把所有的 bitcode 文件读进内存,把他们链接到一起,然后在集成过程中执行 LLVM 的优化器。由于优化器可以看到更多的代码范围,它就能做到内联、常量传播、更激进的无用代码删除的优化。当现代编译器支持 LTO 时,大部分会有较高的代价和缓慢的序列化过程,在 LLVM 中 LTO 就自然得多,因为有 IR 这个中间格式。

Install-time optimization is the idea of delaying code generation even later than link time, all the way to install time, as shown in Figure 11.7. Install time is a very interesting time (in cases when software is shipped in a box, downloaded, uploaded to a mobile device, etc.), because this is when you find out the specifics of the device you're targeting. In the x86 family for example, there are broad variety of chips and characteristics. By delaying instruction choice, scheduling, and other aspects of code generation, you can pick the best answers for the specific hardware an application ends up running on.

安装时优化是推迟代码生成甚至在链接之后。安装时优化是有趣的时间段(这个阶段软件被打包、下载、上传到移动设备),因为你可以知道你的设备的特定目标。在 x86 中,有大量的芯片和特性。通过推迟指令的选择,调整和代码生成的其他部分,你可以找到特定平台的更好的优化方式。

Unit Testing the Optimizer

Compilers are very complicated, and quality is important, therefore testing is critical. For example, after fixing a bug that caused a crash in an optimizer, a regression test should be added to make sure it doesn't happen again. The traditional approach to testing this is to write a .c file (for example) that is run through the compiler, and to have a test harness that verifies that the compiler doesn't crash. This is the approach used by the GCC test suite, for example.

编译器非常复杂,而且性能非常重要,因为测试是很关键的。比如修复了某个优化器导致的崩溃 bug,那么就应该执行回归测试保证不会再犯。传统的方式是写一个 .c 文件让编译器来执行,GCC 就是用的这种方式。

The problem with this approach is that the compiler consists of many different subsystems and even many different passes in the optimizer, all of which have the opportunity to change what the input code looks like by the time it gets to the previously buggy code in question. If something changes in the front end or an earlier optimizer, a test case can easily fail to test what it is supposed to be testing.

这种方式的问题是编译器包含有各种各样的子系统以及各种不同的优化器的 pass,所有这些都有机会去修改输入的代码,如果一旦发生了修改,那么测试用例很可能会报错。

By using the textual form of LLVM IR with the modular optimizer, the LLVM test suite has highly focused regression tests that can load LLVM IR from disk, run it through exactly one optimization pass, and verify the expected behavior. Beyond crashing, a more complicated behavioral test wants to verify that an optimization is actually performed. Here is a simple test case that checks to see that the constant propagation pass is working with add instructions:

通过使用 LLVM IR 的文本格式,LLVM 的测试套件可以更高效地处理回归测试,把 IR 从磁盘中加载,执行特定的优化 pass,然后验证其行为。这种方法还可以看到实际的优化。

; RUN: opt < %s -constprop -S | FileCheck %s
define i32 @test() {
  %A = add i32 4, 5
  ret i32 %A
  ; CHECK: @test()
  ; CHECK: ret i32 9
}

The RUN line specifies the command to execute: in this case, the opt and FileCheck command line tools. The opt program is a simple wrapper around the LLVM pass manager, which links in all the standard passes (and can dynamically load plugins containing other passes) and exposes them through to the command line. The FileCheck tool verifies that its standard input matches a series of CHECK directives. In this case, this simple test is verifying that the constprop pass is folding the add of 4 and 5 into 9.

RUN 指令表示执行,这里使用 opt 和 FileCheck 工具。opt 是 LLVM pass 管理的包装器,链接有所有的 pass。FileCheck 验证输出是否匹配。在上面的案例当中,是验证 constprop pass 常量传播会把 4 加 5 输出为 9。

Automatic Test Case Reduction with BugPoint

When a bug is found in a compiler or other client of the LLVM libraries, the first step to fixing it is to get a test case that reproduces the problem. Once you have a test case, it is best to minimize it to the smallest example that reproduces the problem, and also narrow it down to the part of LLVM where the problem happens, such as the optimization pass at fault. While you eventually learn how to do this, the process is tedious, manual, and particularly painful for cases where the compiler generates incorrect code but does not crash.

当发现编译器的 bug,第一步是去用测试用例来重现它。一旦有了测试用例,就更好地减少 bug 的测试用例了,以及可以缩小问题发现的范围,比如某个优化的 pass 导致的问题。当你学会了怎么去操作,这个测试用例就是冗余的、有问题的。

The LLVM BugPoint tool7 uses the IR serialization and modular design of LLVM to automate this process. For example, given an input .ll or .bc file along with a list of optimization passes that causes an optimizer crash, BugPoint reduces the input to a small test case and determines which optimizer is at fault. It then outputs the reduced test case and the opt command used to reproduce the failure. It finds this by using techniques similar to "delta debugging" to reduce the input and the optimizer pass list. Because it knows the structure of LLVM IR, BugPoint does not waste time generating invalid IR to input to the optimizer, unlike the standard "delta" command line tool.

LLVM BugPoint 工具使用 IR 序列化以及模块化的设计来自动操作。比如,给定输入 .ll 或者 .bc 文件,在一系列的优化 pass 之后会导致崩溃,BugPoint 减少输入为小的测试用例以及分析哪个优化操作导致崩溃。然后它输出减少后的测试用例以及使用 opt 来重现问题。它通过增量调试的方式去减少输入和优化的 pass 列表。因为它知晓 LLVM IR 的结构,BugPoint 不会浪费时间生成无效的 IR。

In the more complex case of a miscompilation, you can specify the input, code generator information, the command line to pass to the executable, and a reference output. BugPoint will first determine if the problem is due to an optimizer or a code generator, and will then repeatedly partition the test case into two pieces: one that is sent into the "known good" component and one that is sent into the "known buggy" component. By iteratively moving more and more code out of the partition that is sent into the known buggy code generator, it reduces the test case.

在更复杂的混合编译中,你可以指定输入、代码生成的信息、指定的命令行工具去执行、输出的引用。BugPoint 会首先分析这个问题是优化器引起的还是代码生成引起的,然后会重复地划分测试用例为两部分:一部分是已知的好的部分,另一部分是已知的有问题的部分。通过重复地移除越来越多的代码块,就减少了测试用例的量。

BugPoint is a very simple tool and has saved countless hours of test case reduction throughout the life of LLVM. No other open source compiler has a similarly powerful tool, because it relies on a well-defined intermediate representation. That said, BugPoint isn't perfect, and would benefit from a rewrite. It dates back to 2002, and is typically only improved when someone has a really tricky bug to track down that the existing tool doesn't handle well. It has grown over time, accreting new features (such as JIT debugging) without a consistent design or owner.

BugPoint 是一个简单的工具,为我们省下了大量的测试时间。没有其他开源编译器有如此强大的工具,因为它依赖于良好的中间表示。但是,BugPoint 并非完美,它对于重写有好处。

reference

https://aosabook.org/en/llvm.ht

LLVM实战之模块化设计 Pass之间耦合很小,而Pass之间的依赖信息由LLVM Pass管理器(Pass Manager)来统一管理,在Pass运行的时候会进行解析。它允许自定义选择各个Pass(遍)的执行顺序,也能够自定义选择哪些优化Pass——也就是说,有一些优化对目前的系统是没有帮助的,只有部分优化会针对目前系统。从结果中可以看出,运行deadargelim pass,对第一个函数没有任何影响,但优化对第2个函数有所影响——前一次优化中没有修改的部分代码在本次优化中被改变,无用的参数被消除了。(1)准备测试case。 阅读详情

相关推荐

LLVM基本概念入门

网上关于LLVM的中文资料一直也不多,即使能找到的一些,也都是停留在怎么使用的层面,对于编译器开发工程师入门来说,感觉完全不够,所以我写写基础概念,能帮到大家也挺好的。

SiberiaBear的专栏 1万+

LLVM源码分析

Module类表示LLVM程序中的顶层结构。一个LLVM Module实际上要么是原始程序的一个翻译单元,要么是链接器合并的几个翻译单元的一个组合。Module 模块包含 Functions列表 + GlobalVariables全局变量列 + SymbolTable符号表1.一个Functions列表返回Function列表。当您需要更新列表或执行没有转发方法的复杂操作时,这是必需的。2.一个GlobalVariables全局变量列表。

扬起你的笑脸~把影子藏在身后 1137

LLVM(简介)

LLVM 从2003 年10月24 日发布第一个开源版本 LLVM1.0 以来,截止2020 年第一个季度,已经发布到LLVM10.0.0 版本,十几年间开发者社区也在不断壮大,从 2007 年起至今,每年都会举办 1-2 次 LLVM 开发者大会,在大会上有很多优秀的开发者们分享他们对于LLVM项目的一些技术问题研究。经典的编译器如gcc在设计上都是提供一条龙服务的: 你不需要知道它使用的IR是什么样的,它也不会暴露中间接口来给你操作它的IR。LLVM的核心是一个库,而不是一个具体的二进制程序。

m0_72827793的博客 5559

代码优化利器 LTO 介绍

由于编译器一次只编译优化一个编译单元,所以只是在做局部优化,而利用 LTO,利用链接时的全局视角进行操作,从而得到能够进行更加极致的优化。 1、定义 “Link-Time Optimization.” Any kind of optimization that requires looking at the whole program, LLVM features powerful intermodular optimizations which can be used at link time. L

fcsfcsfcs的博客 4484

LLVM系列:1.设计思想和LLVM IR简介

本文简单介绍了LLVM项目的背景,并针对LLVM中优化器和代码生成器的模块化设计思想进行了介绍,也简单介绍了LLVM IR的特点,包括结构、变量类型、指令格式等。

你的深度学习小站 2204

LLVM | 编译器框架

介绍 LLVM 背景以及传统编译器架构,同时对 LLVM 项目中的 Clang 和 GCC 进行了简单的介绍和分析。

qq_38844835的博客 5841

从字节码到机器码只需1次编译:Python 2026 AOT架构设计图深度解析,附可运行PoC构建清单

解决Python启动慢与运行时开销大问题,提出Python原生AOT编译方案2026架构设计图:基于LLVM后端,支持模块级静态编译,生成无解释器依赖的原生二进制。适用于嵌入式、CLI工具及云函数场景,冷启动速度提升10倍。含可运行PoC构建清单,值得收藏。

LearnPlex的博客 358

LLVM传统编译器介绍

LLVM框架基础

m0_72676337的博客 2222

LLVM编译原理和使用

LLVM简介: LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time),对开发者保持开放,并兼容已有脚本。 LLVM最早的时候是Illinois的一个研究项目,主要负责人是Chris Lattner,他现在就职于A...

六神的博客 6万+

LLVM的编译链工具

通常我们在命令行上调用的clang工具,是Clang驱动程序,因为LLVM本质上只是一个编译器框架,所以需要一个驱动程序把整个编译器的功能串起来,clang能够监控整个编译器的流程,即能够调用到Clang和LLVM的各种库,最终实现编译的功能。来指定输出是汇编文件还是目标文件,若生成是目标文件,llc会调用LLVM中的汇编输出的代码库来工作(注意这个汇编器和gcc的汇编器也不同,它输入的是MI,是一种后端的中间表示)。clang能够调用起来整个编译器的流程,也就是上边其他工具调用的库,它很多都同样会调用。

panpan_jiang1的博客 1776

LLVM 源码分析

LLVM 使用 CMake 作为其主要的构建系统生成器。CMake 本身不直接构建项目,而是根据配置生成特定构建工具(如 Ninja、Make、Visual Studio、Xcode)所需的文件。克隆仓库。必须在源代码树之外创建一个单独的构建目录(不支持源码内构建)。在构建目录中运行cmake命令,指向 LLVM 源码根目录 (),并指定生成器和各种构建选项。生成器 (-G如Ninja(推荐,速度快 ),Xcode。: 控制优化级别和调试信息。可选值包括Debug。

weixin_39145568的博客 1672

LLVM设计架构

LLVM 把编译器移植到新语言只需要实现编译前端,复用已有的优化和后端;LLVM 实现不同组件隔离为单独程序库,易于在整个编译流水线中集成转换和优化 Pass;LLVM 作为实现各种静态和运行时编译语言的通用基础结构。

喜欢打篮球的普通人 1533

【鸿蒙南向开发】OpenHarmony音频驱动audio适配方案

这份鸿蒙(HarmonyOS NEXT)文档包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

HarmonyOS_666的博客 4513

[译] LLVM IR中间码指令集

最近在研究这个东西, 实在百度不到, 最后在谷歌上找到英文手册. 英文手册地址:https://llvm.org/docs/LangRef.html 先说点废话: 国内的IT水平离世界顶级水平差距实在有点大, 个人感觉 有些因素导致这个结果: 1.化身广告商的百度, 想找点专业文章, 没戏. 2.墙. 有用的文档在墙外,不翻墙看不到. 3...

bluehire的专栏 2258

PCRNet: Point Cloud Registration Network using PointNet Encoding

PCRNet算是在ModelNet40这种object-centric数据集上用deep-learning做配准最好入手的一篇文章了,整体架构涉及简洁明了,一句话描述就是简单粗暴,话不多说,直接上网络架构图: Work Flow: 首先对输入source (N×3N \times 3N×3)与template (M×3M \times 3M×3)进行PointNet操作,即MLP + max-pooling后,分别得到描述各自点云的维度为1024的global feature vector:Φ(PS).

dloading7的博客 1648

手机也能跑!5.6MB的AnimeGANv3模型部署实战:从PyTorch到ONNX再到移动端推理

本文详细介绍了如何将轻量级动画生成器AnimeGANv3从PyTorch模型转换为ONNX格式,并部署到移动端进行实时推理。通过5.6MB的极简模型设计和优化策略,实现在手机等边缘设备上的高效动漫风格转换,涵盖模型准备、格式转换、移动端优化及性能调优全流程。

weixin_33724059的博客 383

LLVM(还没译完, 回头再译)

This chapter discusses some of the design decisions that shaped LLVM1, an umbrella project that hosts and develops a set of close-knit low-level toolchain components (e.g., assemblers, compilers, de

Kreats的专栏 971

华硕笔记本+Ubuntu 20.04:用cpupower解决Intel CPU频率上不去/功耗墙问题实战

本文详细介绍了在华硕笔记本Ubuntu 20.04系统下使用cpupower工具解决Intel CPU频率受限和功耗墙问题的实战方法。通过禁用Intel P-State驱动、配置userspace模式以及高级调优技巧,帮助用户突破性能瓶颈,提升编译和计算效率。

weixin_42561476的博客 524

[llvm cookbook] 1、LLVM设计与使用

了解如何把C语言代码编译为LLVM IR(Intermediate representation)及其他多种形式。与其他编译器(如 GNU Compiler Collection) 不同,LLVM 设计目标是成为一系列的库。

hzq_blog 778

坐标偏移不一致或瓦块重名的多个OSGB工程的融合

介绍如何使用实景三维小助手OSGBLab对坐标偏移不一致或瓦块重名的多个OSGB工程的融合

OSGBLab的博客 3232

45.qt quick-qml虚拟软键盘详解(一)

1.qml虚拟键盘介绍 Qt虚拟键盘的主要功能包括: 可定制的键盘布局和风格与动态切换。 带有单词选择的预测性文本输入。 角色预览和替代角色视图。 自动大小写和空格插入。 不同分辨率的可伸缩性。 支持不同的字符集(拉丁,简体/繁体中文,印地语,日语,阿拉伯语,希伯来语,韩语和其他)。 支持大多数常见的输入语言,可以轻松扩展语言支持。 从左到右和从右到左的输入。 硬件键支持2路和5路导航。 手写支持,带有全屏输入的手势。 音频反馈。 跨平台功能。 支持多国语言,高达40多个语言 本

抵抗时间扭曲,坚持做一件有意义的事 3560

【AI系统】LLVM 架构设计和原理

在上一篇文章中,我们详细探讨了 GCC 的编译过程和原理。然而,由于 GCC 存在代码耦合度高、难以进行独立操作以及庞大的代码量等缺点。正是由于对这些问题的意识,人们开始期待新一代编译器的出现。在本文,我们将深入研究 LLVM 的架构设计和原理,以探索其与 GCC 不同之处。

生活需要深度 1284

遇到一个诡异的WiFi网络问题:同一个办公室苹果电脑上不了网,其他电脑都可以

先来把问题掰开揉碎地看清楚:在一个普通的办公室WiFi网络中,所有设备——Windows电脑、安卓手机、甚至是那台老旧的Linux服务器——都能正常联网,唯独苹果电脑(可能是MacBook、iMac或者Mac mini)像被下了魔咒一样,连不上网。这种情况不仅让人抓狂,还透着一股神秘感。为什么偏偏是苹果电脑?难道WiFi路由器对苹果有“偏见”?这些症状都指向一个核心问题:苹果电脑与办公室WiFi之间,似乎存在某种“沟通障碍”。但这障碍到底出在哪里呢?是苹果电脑自己的问题,还是网络设置在“针对”它?

网络技术联盟站 841
上一篇: 【译】CMake 构建工具
下一篇: 【论文阅读】C++ 二进制插桩检测程序缺陷
流左沙
博客等级 码龄11年 46粉丝 55原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值