我正在尝试为 Trees 实现一种代码生成/寄存器分配算法,以支持我的旧算法,我将所有内容都放在堆栈中。现在我正在尝试实现Sethi-Ullman 算法,但仅从我在维基百科和一些网页上找到的内容来看,算法的某些部分对我来说仍然不清楚。
我正在寻找对一些伪代码/C/C++ 工作代码缺少的部分的解释。
1)我应该使用哪种方法来选择免费注册?即,正在使用的寄存器堆栈。我正在使用我认为非常糟糕的东西:交替返回寄存器:如果以前使用的寄存器是 R0,则返回 R1。如果是 R1,则返回 R0,依此类推。它不适用于小表达式。
2) 我应该在label(left) >= K and label(right) >= K什么时候做什么?
这是label和sethi-ullman功能
REG reg()
{
static REG r = REG_NONE;
switch(r) {
case REG_NONE:
r = REG_r0;
break;
case REG_r0:
r = REG_r1;
break;
case REG_r1:
r = REG_r0;
break;
default:
assert(0);
break;
}
return r;
}
void SethiUllman(AST *node)
{
static const int K = 2;
if(node->left != NULL && node->right != NULL) …Run Code Online (Sandbox Code Playgroud) 我一直在研究寄存器分配,并想知道为什么当有更好的方法可以做到时,他们都从实时寄存器列表中构建图表。我认为他们可以做到的方式是当活动寄存器超过可用寄存器的数量时,寄存器可能会溢出。这是一个示例(伪组装):
## ldi: load immediate
## addr: add registers and store in arg 2
## store: store memory at offset from stack pointer
.text
main:
# live registers: {}
ldi %t0, 12 # t0 = 12
# live registers: {t0}
ldi %t1, 8 # t1 = 8
# live registers: {t0, t1}
addr %t0, %t1 # t1 = t0 + t1
# live registers: {t1}
store -4(%sp), %t1 # -4(%sp) = t1
# live registers: {}
exit
Run Code Online (Sandbox Code Playgroud)
我已经在汇编代码中列出了实时寄存器。现在,所有的教程和文本都从这里构建了干扰图,等等。但不是这样(正如我上面提到的),他们可以查看活动寄存器。例如,如果这是一台单1寄存器机器,那么当活动寄存器是 …
compiler-construction assembly register-allocation cpu-registers graph-algorithm
在编译器设计中,为什么调用者不能通过调用者或被调用者寄存器保存安排来调用,而是调用者不能将其使用的寄存器列表(它将在调用者保存安排的情况下推送)传递给被调用者,以便被调用者可以比较其已使用的寄存器列表,用于调用者使用的寄存器.然后只推送真正需要推送的寄存器.我错过了什么吗?
我在GCC有一个场景给我带来了问题.我得到的行为不是我期望的行为.总结一下这种情况,我提出了一些x86-64的新指令,它们是在硬件模拟器中实现的.为了测试这些指令,我正在使用现有的C源代码并使用十六进制对新指令进行手动编码.因为这些指令与现有的x86-64寄存器交互,所以我使用input/output/clobber列表来声明GCC的依赖关系.
发生的事情是,如果我调用一个函数,例如printf,则不会保存和恢复相关寄存器.
例如
register unsigned long r9 asm ("r9") = 101;
printf("foo %s\n", "bar");
asm volatile (".byte 0x00, 0x00, 0x00, 0x00" : /* no output */ : "q" (r9) );
Run Code Online (Sandbox Code Playgroud)
101被分配给r9,内联汇编(本例中为假)依赖于r9.这在没有printf的情况下正确运行,但是当它存在时,GCC不会保存和恢复r9,并且在调用自定义指令时会有另一个值.
我想也许GCC可能秘密地将赋值更改为变量 r9,但是当我这样做时
asm volatile (".byte %0" : /* no output */ : "q" (r9) );
Run Code Online (Sandbox Code Playgroud)
看看汇编输出,确实使用的是%r9.
我正在使用gcc 4.4.5.您认为可能会发生什么?我认为GCC将始终在函数调用中保存和恢复寄存器.有什么方法可以强制执行吗?
谢谢!
编辑:顺便说一句,我正在编译这样的程序
gcc -static -m64 -mmmx -msse -msse2 -O0 test.c -o test
Run Code Online (Sandbox Code Playgroud) 假设你有一个只有 4 个寄存器 A、B、C 和 D 的虚拟机。编译器如何用有限的空间存储如此多的变量?
是否有多种方法可以做到这一点,或者是否有一种可靠的方法可以实现这一点?这个奇特的科学术语是什么?它被认为是一个复杂的问题吗?
compiler-construction register-allocation cpu-registers vm-implementation
(ANSI-C 89)嗨,是否可以将变量声明为静态和寄存器?当我尝试这样做时,我只是按摩错误:multiple storage classes in declaration specifiers
这是代码:
#include <stdio.h>
void f1(static int i);
int main()
{
static register int i;
i = 5;
f1(i);
}
void f1(static int i)
{
static int y =6;
y+=1;
printf("\n Y=%d \n",y);
}
Run Code Online (Sandbox Code Playgroud)
和
我正在尝试按照此链接生成c代码的 IR 表示。c我使用的代码如下
void main() {
int c1 = 17;
int c2 = 25;
int c3 = c1 + c2;
printf("Value = %d\n", c3);
}
Run Code Online (Sandbox Code Playgroud)
我将其另存为const.c. 保存后,我使用以下命令生成.bc文件。
clang -c -emit-llvm const.c -o const.bc
Run Code Online (Sandbox Code Playgroud)
一旦生成.BC文件,我想以此来生成的优化版本使用下面的命令const.bc被命名文件const.reg.bc。
opt -mem2reg const.bc > const.reg.bc
Run Code Online (Sandbox Code Playgroud)
我在生成这些文件时没有任何问题,但由于某种原因,它们完全相同,并且没有发生任何优化。结果应该不同,我的意思是const.reg.bc应该是const.bc文件的优化版本。但由于某种原因,它不会发生。有人可以告诉我我做错了什么吗?
我理解两个变量,比如a1和a2出现在Fortran中的Equivalence(a1,a2)语句中,然后它们占用相同的内存空间.所以说这发生在一个过程中,其中a1和a2都是该过程中的局部变量.
这意味着你不仅可以在内存中拥有a1和a2的副本吗?因为其中一个值将被覆盖.您可以将a1保留在内存位置并将a2保存在整个过程的寄存器中,这样就可以了吗?
我的问题基本上是:你可以将a1保留在整个程序的注册表中吗?
我会说是的...除非你用完了寄存器而a1必须存储回内存.然后你将覆盖a2并失去它的值,然后变量a1和a2实际上将指向a1的值.