问题标签 [register-allocation]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
assembly - 为什么编译器在寄存器分配中构造图?
我一直在研究寄存器分配,想知道为什么他们都从实时寄存器列表中构建图表,而可能有更好的方法来做到这一点。我认为他们可以做到的方式是,当实时寄存器超过可用寄存器的数量时,寄存器可能会溢出。这是一个示例(伪组装):
我已经在汇编代码中列出了实时寄存器。现在,所有的教程和文本都从这里构建干扰图,等等。但不是那样(正如我上面提到的),他们可以查看活动寄存器。例如,如果这是一台单1寄存器机器,那么当活动寄存器为 时{t0, t1},我们将不得不选择一个寄存器进行溢出。我觉得这比构建图表和做所有其他事情来检查我们是否必须溢出寄存器要简单得多。我知道无知不是全球性的(一定有人想到了这一点并认为它不合适),所以我在这里看不到什么?
x86 - 寄存器分配 --- 如何利用和溢出调用者保存的寄存器
我了解到,如果caller saved registers (rax rdx rcx rsi rdi r8 r9 r10 r11)被调用者使用了任何一个,那么它必须在调用者指令之前保存并call在调用者指令之后恢复。
通过下面的例子,
笔记
变量
a - g应使用所有callee saved registers (rbp rsp rbx r12 r13 r14 r15). 而且我们不能同时使用rbp或rsp,因为必须使用其中任何一个来寻址堆栈内存。和
read来自print一些外部编译单元。main因此,当我们编译当前编译单元时,特别是在为函数分配寄存器期间,我们并不真正了解它们的调用者保存寄存器的使用情况。
在godbolt中,-O3它编译为以下
笔记
变量
a溢出到12(%rsp).我们不需要溢出任何东西,
caller saved registers因为它们根本没有被使用,结果证明在这里更有效。
我的问题
caller saved registers如果我们不使用它们,看起来我们真的不需要处理溢出的问题。因此,我们什么时候应该使用caller saved registers?对于像这样的被调用者,
read并且print由于我们不知道他们的寄存器使用情况,我们应该如何为caller saved registers?
谢谢
assembly - “fomit-frame-pointer”有什么好处?
“-fomit-frame-pointer”表示我们不必 pushq %rbp 和移动 %rsp, %rbp 的方式;我们只需要更改 %rsp 的值。据我认为,处理基本指针的堆栈帧和没有它的堆栈帧在好处方面没有差异。你能解释一下“不处理 %ebp 的堆栈帧”有什么好处吗?
c - 为什么 C 中的这个堆栈变量不在寄存器中?
我对如何执行缓冲区溢出攻击以及寄存器分配在编译器中的工作方式有合理的理解。
让我感到困惑的是,为什么 C 程序的堆栈上有这么多东西。考虑这个易受攻击的程序:
让我们运行它
好的,所以 str 按原样被覆盖int a。但为什么int a甚至在堆栈上?做类似(x86 asm)之类的事情不是最简单的吗
现在我们的内存流量减少了,因为堆栈上没有任何东西,代码也少了很多。
tl;博士为什么int a在堆栈上?
assembly - 影响 GCC 内联汇编中内存操作数寻址模式的早期破坏行为不正确的具体示例?
以下摘自GCC 手册的 Extended Asm 文档asm,关于使用关键字在 C 中嵌入汇编指令:
如果一个输出参数 ( a ) 允许寄存器约束,而另一个输出参数 ( b ) 允许内存约束,则会出现同样的问题。GCC 生成的用于访问 b中的内存地址的代码可以包含可能由a共享的寄存器,并且 GCC 将这些寄存器视为 asm 的输入。如上所述,GCC 假设在写入任何输出之前消耗了此类输入寄存器。如果 asm 语句在使用 b 之前写入 a,这种假设可能会导致不正确的行为。结合'&' 在a上带有寄存器约束的修饰符确保修改a不会影响b引用的地址. 否则,如果在使用b之前修改a ,则b的位置未定义 。
a斜体句子表示如果 asm 语句在使用之前写入,则可能存在“不正确的行为” b。
我想不通这种“不正确的行为”是如何发生的,所以我希望有一个具体的 asm 代码示例来演示“不正确的行为”,以便我对这一段有深刻的理解。
当两个这样的asm代码并行运行时,我可以感知到问题,但是上面这段没有提到多处理场景。
如果我们只有一个 CPU 一个核心,能否请您显示一个可能会产生这种不正确行为的 asm 代码,即修改a会影响所引用的地址,b从而导致位置b未定义。
我唯一熟悉的汇编语言是 Intel x86 汇编,所以请使示例针对该平台。
timer - 如何在 stm32 微控制器上读取 TIMx CNT 寄存器:等号问题
我一直在玩核板 f411RE,特别是通用定时器 TIM9、TIM10、TIM11。我想使用 TIM10(16 位定时器)通过启用它并让它运行来测量时间,然后使用存储在 TIM10->CNT 中的值通过使用 if 条件来做出决定(是否打开 LED) .
当我使用 <,>, <=, >= 运算符将计数器 (TIM10->CNT) 的值与任何其他数字进行比较时,例如:
甚至:
一切都按我预期的那样工作,我的功能按照我想要的方式运行。
每当我尝试使用等号将定时器计数器寄存器与不为零的数字(表示为“任何值”)进行比较时,就会出现问题,如下所示:
正如上面的评论中所表达的,每当我明确使用等号 ( == ) 且数字不为零时,由该条件定义的块不会被执行。似乎我可以使用和比较 TIM10 计数器的唯一方法是使用不等式运算符(>、<、=>、>=)或将其显式与零进行比较。
到目前为止,我还没有发布实际代码,因为这是唯一困扰我的部分,所有其他组件都像魅力一样工作。无论如何,这是我的代码的一瞥:
伪代码:
--- 程序开始 ---
--- TIM10 -> CNT 初始化为零 ---
---while循环开始---
---读取 TIM10->CNT 寄存器并将其值存储在变量中---
---按下按钮启用 TIM10---
---如果在计数器已经运行时再次按下按钮,则停止计时器并将其值存储在一个变量中以用于下一个函数---
---根据经过时间的值打开或关闭 LED 的功能 TIM10 -> CNT ---
实际的 C++ 代码是:
关于为什么我不能将“==”运算符与定时器计数器寄存器一起使用的帮助和评论将不胜感激。
pd:实际上,任何评论都会受到赞赏。
pd2:有人可能会认为延迟在某种程度上干扰了最后一个 if 条件,但实际上放在那里的指令并不重要,由于“==”的使用,该块将不会执行
pd3:正如我之前所说,问题似乎是明确使用“==”,因为我已经尝试了代码的所有其他部分并且它们完美地工作(时钟配置,定时器配置,GPIO配置以及写入和读取每个相应引脚的方法)
assembly - 为什么编译器将结果存储到单个寄存器而不是在连续存储到内存之前没有很多不同的寄存器?
例如,看看这个由gcc.
它可以满足我的要求,但我注意到的一件事是,结果总是先存储到内存中,ymm0然后再存储到内存中。我的意思是,我知道vpand不能直接对内存进行操作,但是这不是更有效吗?
这样一来,我认为可以并行完成更多的操作,因为没有通过 ymm0.
它使用了更多的寄存器,但是这个函数无论如何都使用了全部 16 ymms,并且在这部分之后,新的值被加载到每个寄存器中,所以使用更多的寄存器并不是什么问题。
我查了一下clang,它产生了相同的代码,只是寄存器号不同。
如果我使用第二种寄存器分配方式直接在汇编中编写,我可以期待明显的加速吗?
我实际上可以测试并查看,但是直接在汇编中编写对我来说并不是一件容易的事,还有其他部分需要处理,所以我问这个问题是为了首先更好地了解使用不同的寄存器进行连续内存存储是否可以实际提高性能。
