zoukankan      html  css  js  c++  java
  • C2

    写点C2中memory subgraph中涉及的反依赖问题。没有提纲,心意所至,笔向所指。

    有这样一段java代码...

     static class Foo {
         public int a = 2;
         public int b = 4;
     }
    
    Foo test(int x) {
        Foo f1 = new Foo();
        Foo f2 = new Foo();
        f1.a = 42; // LINE9
        f2.a = f1.a;  // LINE10
        f1.a = 24; // LILNE11
        return f1;
    }
    

    它对应的ir局部如下,这里我们只关心line9-11:

    image

    C2稍微做了些优化,将line10变成了f2.a=42,三条赋值分配对应188#StoreI,192#StoreI和195#StoreI,它们依次执行,和代码顺序一致,这里有个问题?C2如何构造IR的时候如何知道192#StoreI的in(Memory)是188#StoreI,答案就是通过alias type。

    简单来说,alias type用来描述memory slice信息,它可以不同粒度的描述memory slice。比如下面的例子,f.a和f2.a访问的memory slice的alias type一样(Reduced(Foo+12),f.b和f2.b同理alias type一样(Reduced)Foo+16)。

    int test() {
        // @ <2>     +any in BotPTR *+bot
        // @ <3>     +0   in rawptr:BotPTR
        // @ <4>     +0   in java/lang/Object *
        // @ <5>  RO +8   in java/lang/Object+8 * [narrowklass]
        // @ <6>     +12  in Reduced$Foo+12 *
        // @ <7>     +16  in Reduced$Foo+16 *
        // @ <8>  RO +172 in klass java/lang/Object: 0x00007fff54006cb8+172 *
        Foo f = new Foo();
        Foo f2 = new Foo();
        f.a  =12;
        f.b = 23;
        f2.a = 6;
        f2.b = 7;
        return f.a+f2.b;
    }
    

    回到例子中,由于三个赋值访问的都是Foo#a字段,所以它们相关。甚至,我们可以把上面的赋值改成:
    f1.a=42; f2.a=25;
    生成的StoreI也会关联起来

    image

    上面的情况中,赋值语句的rhs都是常量,但是很多情况下rhs也可以是一个读内存值,这个时候我们需要一个LoadX节点,它的输入是一个内存地址,得到的是内存地址里面的值,行为和解引用一样。下面的java代码:

    static int i=2,j=3,k=9;
    int test(int x) {
        j = i;     // 30#StoreI
        i = k;     // 35#StoreI
        return i ; // at this point, i==9,j==2
    }
    

    35#StoreI相当于i=k,30#StoreI相当于j=i,具体点27#LoadI是读i的值,33#LoadI是读k的值。执行流程如下:

    1. 执行27#LoadI,读取i的值,相当于tmp=i 。此时tmp==2
    2. 执行35#StoreI,读取k的值,然后赋值给i所在内存。此时i == 9
    3. 执行30#StoreI,将27#LoadI读取到的i的值赋值给j,相当于j=tmp。此时j==2
    4. 最终 i==9,j==2

    image

    上面的IR有个比较严重的问题:27#LoadI(读i值)和35#StoreI(给i赋值)访问的memory slice的alias type是相同的,但是两者没有依赖关系的。想象一下,假如先执行35#StoreI,后执行27#LoadI会发生什么?

    1. 执行35#StoreI,读取k的值,然后赋值给i所在内存。此时i == 9
    2. 执行27#LoadI,读取i的值,相当于tmp=i 。此时tmp==9
    3. 执行30#StoreI,将27#LoadI读取到的i的值赋值给j,相当于j=tmp。此时j==9
    4. 最终i==9,j==9

    35#StoreI和27#LoadI没有依赖关系,不同的执行顺序可能导致不同的结果。

    要解决这个问题,我们需要插入反依赖(PhaseCFG::insert_anti_dependences),这一步是在GCM阶段完成,GCM之后的IR如下图

    image

    可以看到8#storeI多了一条12#loadI的输入。当执行8#storeI的时候强制要求读取k和i的值,保证了12#lloadI先于8#storeI执行。这条从12#loadI流出到8#storeI的表就叫做反依赖,注意反依赖说的是load依赖store,主体是load。C2在处理反依赖问题的时候,除了插入反依赖的边之外,还有一种解决方案,它也可能将load节点所在的LCA block强制上移,使得load节点可以放置的early block-LCA block均处于store节点之上,用这样的方式来保证store不会先于load执行。

  • 相关阅读:
    WPF之窗体说明
    WPF之基本概念
    WPF学习之button
    写一本”错误百出”的C语言学习教程(一)
    JSP的工作原理-还是没理解--多看点再写。
    Java将中文转换成unicode字符。
    postgres 导出数据到csv 文件
    python小试身手-文件重命名,文件复制和压缩(.gz)
    python 环境安装 mark下。
    JRE,JVM,JDK的区别---粘自百度知道、
  • 原文地址:https://www.cnblogs.com/kelthuzadx/p/15168843.html
Copyright © 2011-2022 走看看