首页 > 编程语言 >LLVM IR与C++ MUL函数代码

LLVM IR与C++ MUL函数代码

时间:2023-01-07 06:11:27浏览次数:67  
标签:LLVM int i32 IR C++ MUL o0

LLVM IRC++ MUL函数代码

使用LLVM IR写程序

熟悉LLVM IR最好的办法就是使用IR写几个程序。在开始写之前,建议先花30分钟-1个小时再粗略阅读下官方手册(https://llvm.org/docs/LangRef.html),熟悉下都有哪些指令的类型。接下来我们通过两个简单的case熟悉下LLVM IR编程的全部流程。

下面是一个循环加法的函数片段。这个函数一共包含三个Basic Block,loop、loop_body和final。其中loop是整个函数的开始,loop_body是函数的循环体,final是函数的结尾。在第5行和第6行,我们使用phi节点来实现结果和循环变量。

define i32 @ir_loopadd_phi(i32*, i32){  br label %loop      loop:  %i = phi i32 [0,%2], [%newi,%loop_body]  %res = phi i32[0,%2], [%new_res, %loop_body]  %break_flag = icmp sge i32 %i, %1  br i1 %break_flag, label %final, label %loop_body       loop_body:  %addr = getelementptr inbounds i32, i32* %0, i32 %i  %val = load i32, i32* %addr, align 4  %new_res = add i32 %res, %val  %newi = add i32 %i, 1  br label %loopfinal:  ret i32 %res;}

下面是一个数组冒泡排序的函数片段。这个函数包含两个循环体。LLVM IR实现循环本身就比较复杂,两个循环嵌套会更加复杂。如果能够用LLVM IR实现一个冒泡算法,基本上就理解了LLVM的整个逻辑了。

define void @ir_bubble(i32*, i32) {  %r_flag_addr = alloca i32, align 4  %j = alloca i32, align 4  %r_flag_ini = add i32 %1, -1  store i32 %r_flag_ini, i32* %r_flag_addr, align 4  br label %out_loop_headout_loop_head:  ;check break  store i32 0, i32* %j, align 4  %tmp_r_flag = load i32, i32* %r_flag_addr, align 4  %out_break_flag = icmp sle i32 %tmp_r_flag, 0  br i1 %out_break_flag, label %final, label %in_loop_head  in_loop_head:    ;check break    %tmpj_1 = load i32, i32* %j, align 4    %in_break_flag = icmp sge i32 %tmpj_1, %tmp_r_flag    br i1 %in_break_flag, label %out_loop_tail, label %in_loop_body  in_loop_body:    ;read & swap    %tmpj_left = load i32, i32* %j, align 4    %tmpj_right = add i32 %tmpj_left, 1    %left_addr = getelementptr inbounds i32, i32* %0, i32 %tmpj_left    %right_addr = getelementptr inbounds i32, i32* %0, i32 %tmpj_right    %left_val = load i32, i32* %left_addr, align 4    %right_val = load i32, i32* %right_addr, align 4    ;swap check    %swap_flag = icmp sge i32 %left_val, %right_val    %left_res  = select i1 %swap_flag, i32 %right_val, i32 %left_val     %right_res = select i1 %swap_flag, i32 %left_val, i32 %right_val    store i32 %left_res, i32* %left_addr, align 4    store i32 %right_res, i32* %right_addr, align 4    br label %in_loop_end  in_loop_end:    ;update j    %tmpj_2 = load i32, i32* %j, align 4    %newj = add i32 %tmpj_2, 1    store i32 %newj, i32* %j, align 4    br label %in_loop_headout_loop_tail:  ;update r_flag   %tmp_r_flag_1 = load i32, i32* %r_flag_addr, align 4  %new_r_flag = sub i32 %tmp_r_flag_1, 1  store i32 %new_r_flag, i32* %r_flag_addr, align 4  br label %out_loop_headfinal:  ret void}

我们把如上的LLVM IR用clang编译器编译成object文件,然后和C语言写的程序链接到一起,即可正常调用。在上面提到的case中,我们只使用了i32、i64等基本数据类型,LLVM IR中支持struct等高级数据类型,可以实现更为复杂的功能。

2.3 使用LLVM API实现Codegen

编译器本质上就是调用各种各样的API,根据输入去生成对应的代码,LLVM Codegen也不例外。在LLVM内部,一个函数是一个class,一个Basic Block试一个class, 一条指令、一个变量都是一个class。用LLVM API实现codegen就是根据需求,用LLVM内部的数据结构去实现相应的IR。

    Value *constant = Builder.getInt32(16);    Value *Arg1 = fooFunc->arg_begin();    Value *val = createArith(Builder, Arg1, constant);    Value *val2 = Builder.getInt32(100);    Value *Compare = Builder.CreateICmpULT(val, val2, "cmptmp");    Value *Condition = Builder.CreateICmpNE(Compare, Builder.getInt1(0), "ifcond");    ValList VL;    VL.push_back(Condition);    VL.push_back(Arg1);    BasicBlock *ThenBB = createBB(fooFunc, "then");    BasicBlock *ElseBB = createBB(fooFunc, "else");    BasicBlock *MergeBB = createBB(fooFunc, "ifcont");    BBList List;    List.push_back(ThenBB);    List.push_back(ElseBB);    List.push_back(MergeBB);    Value *v = createIfElse(Builder, List, VL);

如上是一个用LLVM API实现codegen的例子。其实这就是个用C++写IR的过程,如果知道如何写IR的话,只需要熟悉下这套API就可以了。这套API提供了一些基本的数据结构,比如指令、函数、基本块、llvm builder等,然后我们只需要调用相应的函数去生成这些对象即可。一般来说,首先我们先生成函数的原型,包括函数名字、参数列表、返回类型等。然后我们在根据函数的功能,确定都需要有哪些Basic Block以及Basic Block之间的跳转关系,然后生成相应的Basic。最后我们再按照一定的顺序去给每个Basic Block填充指令。逻辑是,这个流程和用LLVM IR写代码是相仿的。

3. Codegen技术分析

如果我们用上文所描述的方法,生成一些简单的函数,并且用C写出对应的版本进行性能对比,我们就会发现,LLVM IR的性能并不会比C快。一方面,计算机底层执行的是汇编,C语言本身和汇编是非常接近的,了解底层的程序员往往能够从C代码中推测出大概会生成什么样的汇编。另一方面,现代编译器往往做了很多优化,一些大大减轻了程序员的优化负担。因此,使用LLVM IR进行Codegen并不会获得比手写C更好的性能,而且使用LLVM Codegen有一些明显的缺点。想要真正用好LLVM,我们还需要熟悉LLVM的特点。

3.1 缺点分析

缺点1:开发难。实际开发中几乎不会有工程使用汇编作为主要开发语言,因为开发难度太大了,有兴趣的小伙伴可以试着写个快排感受一下。即使是数据库、操作系统这样的基础软件,往往也只是在少数的地方会用到汇编。使用LLVM IR开发会有类似的问题。比如上文展示的最复杂例子是冒泡算法。开发者用C写个冒泡只需要几分钟,但是用LLVM IR写个冒泡可能要一个小时。另外,LLVM IR很难处理复杂的数据结构,比如结构体、类。除了LLVM IR中的那些基本数据结构外,新增一个复杂的数据结构非常难。因此在实际的开发当中,采用Codegen会导致开发难度指数级上升。

缺点2:调试难。开发者通常通过单步跟踪的方式去调试代码,但是LLVM IR是不支持的。一旦代码出问题,只能是人肉一遍一遍看LLVM IR。如果懂汇编的话,可以通过单步跟踪生成的汇编进行调试,但是汇编语言和IR之间并不是简单的映射关系,因此只能一定程度上降低调试难度,并不完全解决调试的问题。

缺点3: 运行成本。生成LLVM IR往往很快,但是生成的IR需要调用LLVM 中的工具进行优化、以及编译成二进制文件,这个过程是需要时间的(请联想一下GCC编译的速度)。在数据库的开发过程中,我们的经验值是每个函数大约需要10ms-100ms的codegen成本。大部分的时间花在了优化IR和IR到汇编这两步。

3.2 适用场景

了解了LLVM Codegen的缺点,我们才能去分析其优点、选择合适场景。下面这部分是团队在开发过程中总结的适合使用LLVM Codegen的场景。

场景1:Java/python等语言。上文中提到过LLVM IR并不会比C快,但是会比Java/python等语言快啊。例如在Java中,有时候为了提升性能,会通过JNI调用一些C的函数提升性能。同理,Java也可以调用LLVM IR生成的函数提升性能。

场景2:硬件和语言不兼容。LLVM支持多种后端,比如X86、ARM和GPU。对于一些硬件与语言不兼容的场景,可以利用LLVM实现兼容。例如如果我们的系统是用Java语言开发、想要调用GPU,可以考虑用LLVM IR生成GPU代码,然后通过JNI的方法进行调用。这套方案不仅支持NVIDIA的GPU,也支持AMD的GPU,而且对应生成的IR也可以在CPU上执行。

场景3:逻辑简化。以数据库为例,数据库执行引擎在执行过程中需要做大量的数据类型、算法逻辑相关的判断。这主要是由于SQL中的数据类型和逻辑,很多是在数据库开发时无法确定的,只能在运行时决定。这一部分过程,也被称为“解释执行”。我们可以利用LLVM在运行时生成代码,由于这个时候数据类型和逻辑已经确定,我们可以在LLVM IR中删除那些不必要的判断操作,从而实现性能的提升。

4. LLVM在数据库中的应用

在数据库当中,团队是用LLVM来进行表达式的处理,接下来我们以PostgreSQL数据库和云原生数据仓库AnalyticDB PostgreSQL为对比,解释LLVM的应用方法。

PostgreSQL为了实现表达式的解释执行,采用了一套“拼函数”的方案。PostgreSQL中实现了大量C函数,比如加减法、大小比较等,不同类型的都有。SQL在生成执行计划阶段会根据表达式符号的类型和数据类型选择相应的函数、把指针存下来,等执行的时候再调用。因此对于 "a > 10 and b < 5"这样的过滤条件,假设a和b都是int32,PostgreSQL实际上调用了“Int8AndOp(Int32GT(a, 10), Int32LT(b, 5))”这样一个函数组合,就像搭积木一样。这样的方案有两个明显的性能问题。一方面这种方案会带来比较多次数的函数调用,函数调用本身是有成本的。另一方面,这种方案必须要实现一个统一的函数接口,函数内部和外部都需要做一些类型转换,这也是额外的性能开销。Odyssey使用LLVM 进行codegen,可以实现最小化的代码。因为在SQL下发以后,数据库是知道表达式的符号和输入数据的类型的,因此只需要根据需求选取相应的IR指令就可以了。因此只需要三条IR指令,就可以实现这个表达式,然后我们把表达式封装成一个函数,就可以在执行的时候调用了。这次操作,把多次函数调用简化成了一次函数调用,大大减少了指令的总数量。

// 样例SQLselect count(*) from table where a > 10 and b < 5;// PostgreSQL解释执行方案:多次函数调用result = Int8AndOp(Int32GT(a, 10), Int32LT(b, 5));// AnalyticDB PostgreSQL方案:使用LLVM codegen生成最小化底层代码%res1 = icmp ugt i32 %a, 10;%res2 = icmp ult i32 %b, 5; %res = and i8 %res1, %res2;

在数据库中,表达式主要出现在几个场景。一类是过滤条件,通常出现在where条件中。一类是输出列表,一般跟在select之后。有些算子,比如join、agg等,它的判断条件中也可能会出现一些比较复杂的表达式。因此表达式的处理是会出现在数据库执行引擎的各个模块的。在AnalyticDB PostgreSQL版中,开发团队抽象出了一个表达式处理框架,通过LLVM Codegen来处理这些表达式,从而提高了执行引擎的整体性能。

 

 

 LLVM作为一个流行的开源编译框架,近年来被用于数据库、AI等系统的性能加速。由于编译器理论本身门槛较高,因此LLVM的学习有一定的难度。而且从工程上,还需要对LLVM的工程特点和性能特征有比较准确的理解,才能找到合适的加速场景。阿里云数据库团队的云原生数据仓库产品AnalyticDB PostgreSQL版基于LLVM实现了一套运行时的表达式处理框架,能够有效地提高系统在进行复杂数据分析时地性能。

C++ MUL函数代码示例

本文整理汇总了C++中MUL函数的典型用法代码示例。

一共展示了MUL函数的15个代码示例。

示例1: gradMag

void gradMag( float *I, float *M, float *O, int h, int w, int d, bool full ) {
    int x, y, y1, c, h4, s;
    float *Gx, *Gy, *M2;
    __m128 *_Gx, *_Gy, *_M2, _m;
    float *acost = acosTable(), acMult = 10000.0f;
    // allocate memory for storing one column of output (padded so h4%4==0)
    h4 = (h % 4 == 0) ? h : h - (h % 4) + 4;
    s = d * h4 * sizeof(float);
    M2 = (float*) alMalloc(s, 16);
    _M2 = (__m128*) M2;
    Gx = (float*) alMalloc(s, 16);
    _Gx = (__m128*) Gx;
    Gy = (float*) alMalloc(s, 16);
    _Gy = (__m128*) Gy;
    // compute gradient magnitude and orientation for each column
    for ( x = 0; x < w; x++ ) {
        // compute gradients (Gx, Gy) with maximum squared magnitude (M2)
        for (c = 0; c < d; c++) {
            grad1( I + x * h + c * w * h, Gx + c * h4, Gy + c * h4, h, w, x );
            for ( y = 0; y < h4 / 4; y++ ) {
                y1 = h4 / 4 * c + y;
                _M2[y1] = ADD(MUL(_Gx[y1], _Gx[y1]), MUL(_Gy[y1], _Gy[y1]));
                if ( c == 0 ) { continue; }
                _m = CMPGT( _M2[y1], _M2[y] );
                _M2[y] = OR( AND(_m, _M2[y1]), ANDNOT(_m, _M2[y]) );
                _Gx[y] = OR( AND(_m, _Gx[y1]), ANDNOT(_m, _Gx[y]) );
                _Gy[y] = OR( AND(_m, _Gy[y1]), ANDNOT(_m, _Gy[y]) );
            }
        }
        // compute gradient mangitude (M) and normalize Gx
        for ( y = 0; y < h4 / 4; y++ ) {
            _m = MINsse( RCPSQRT(_M2[y]), SET(1e10f) );
            _M2[y] = RCP(_m);
            if (O) { _Gx[y] = MUL( MUL(_Gx[y], _m), SET(acMult) ); }
            if (O) { _Gx[y] = XOR( _Gx[y], AND(_Gy[y], SET(-0.f)) ); }
        };
        memcpy( M + x * h, M2, h * sizeof(float) );
        // compute and store gradient orientation (O) via table lookup
        if ( O != 0 ) for ( y = 0; y < h; y++ ) { O[x * h + y] = acost[(int)Gx[y]]; }
        if ( O != 0 && full ) {
            y1 = ((~size_t(O + x * h) + 1) & 15) / 4;
            y = 0;
            for ( ; y < y1; y++ ) { O[y + x * h] += (Gy[y] < 0) * PI; }
            for ( ; y < h - 4; y += 4 ) STRu( O[y + x * h],
                                                  ADD( LDu(O[y + x * h]), AND(CMPLT(LDu(Gy[y]), SET(0.f)), SET(PI)) ) );
            for ( ; y < h; y++ ) { O[y + x * h] += (Gy[y] < 0) * PI; }
        }
    }
    alFree(Gx);
    alFree(Gy);
    alFree(M2);
}

示例2: main

    int a,b;
    double c,d;
 
    printf("Two int Input : ");
    scanf("%d %d",&a,&b);
    printf("%d * %d = %d\n",a,b,MUL(a,b));
 
    printf("Two double Input : ");
    scanf("%lf %lf",&c,&d);
    printf("%lf * %lf = %lf\n",c,d,MUL(c,d));
 
    return 0;
}

示例3: MUL

  unsigned p[2], q[2], r[2], carry0, carry1;
  
  MUL(a[0], x[0], p);
  ADDEQU(p[0], c, carry0);
  ADDEQU(p[1], carry0, carry1);
  MUL(a[0], x[1], q);
  ADDEQU(p[1], q[0], carry0);
  MUL(a[1], x[0], r);
  x[2] = LOW(carry0 + carry1 + CARRY(p[1], r[0]) + q[1] + r[1] +
         a[0] * x[2] + a[1] * x[1] + a[2] * x[0]);
  x[1] = LOW(p[1] + r[0]);
  x[0] = LOW(p[0]);
}

示例4: oob

    // @brief checks if streamout buffer is oob
    // @return <i1> true/false
    Value* oob(const STREAMOUT_COMPILE_STATE& state, Value* pSoCtx, uint32_t buffer)
    {
        Value* returnMask = C(false);
 
        Value* pBuf = getSOBuffer(pSoCtx, buffer);
 
        // load enable
        // @todo bool data types should generate <i1> llvm type
        Value* enabled = TRUNC(LOAD(pBuf, { 0, SWR_STREAMOUT_BUFFER_enable }), IRB()->getInt1Ty());
 
        // load buffer size
        Value* bufferSize = LOAD(pBuf, { 0, SWR_STREAMOUT_BUFFER_bufferSize });
        
        // load current streamOffset
        Value* streamOffset = LOAD(pBuf, { 0, SWR_STREAMOUT_BUFFER_streamOffset });
 
        // load buffer pitch
        Value* pitch = LOAD(pBuf, { 0, SWR_STREAMOUT_BUFFER_pitch });
 
        // buffer is considered oob if in use in a decl but not enabled
        returnMask = OR(returnMask, NOT(enabled));
 
        // buffer is oob if cannot fit a prims worth of verts
        Value* newOffset = ADD(streamOffset, MUL(pitch, C(state.numVertsPerPrim)));
        returnMask = OR(returnMask, ICMP_SGT(newOffset, bufferSize));
 
        return returnMask;
    }

示例5: MUL

gen8_vec4_generator::generate_gs_set_write_offset(struct brw_reg dst,
                                                  struct brw_reg src0,
                                                  struct brw_reg src1)
{
   /* From p22 of volume 4 part 2 of the Ivy Bridge PRM (2.4.3.1 Message
    * Header: M0.3):
    *
    *     Slot 0 Offset. This field, after adding to the Global Offset field
    *     in the message descriptor, specifies the offset (in 256-bit units)
    *     from the start of the URB entry, as referenced by URB Handle 0, at
    *     which the data will be accessed.
    *
    * Similar text describes DWORD M0.4, which is slot 1 offset.
    *
    * Therefore, we want to multiply DWORDs 0 and 4 of src0 (the x components
    * of the register for geometry shader invocations 0 and 1) by the
    * immediate value in src1, and store the result in DWORDs 3 and 4 of dst.
    *
    * We can do this with the following EU instruction:
    *
    *     mul(2) dst.3<1>UD src0<8;2,4>UD src1   { Align1 WE_all }
    */
   default_state.access_mode = BRW_ALIGN_1;
   gen8_instruction *inst =
      MUL(suboffset(stride(dst, 2, 2, 1), 3), stride(src0, 8, 2, 4), src1);
   gen8_set_mask_control(inst, BRW_MASK_DISABLE);
   default_state.access_mode = BRW_ALIGN_16;
}

示例6: LEA

    // Get the horizontal tile pos into tempReg1.
    LEA(32, tempReg1, MScaled(uReg, SCALE_4, 0));
    // Note: imm8 sign extends negative.
    AND(32, R(tempReg1), Imm8(~127));
 
    // Add vertical offset inside tile to tempReg1.
    LEA(32, tempReg2, MScaled(vReg, SCALE_4, 0));
    AND(32, R(tempReg2), Imm8(31));
    LEA(32, tempReg1, MComplex(tempReg1, tempReg2, SCALE_4, 0));
    // Add srcReg, since we'll need it at some point.
    ADD(64, R(tempReg1), R(srcReg));
 
    // Now find the vertical tile pos, and add to tempReg1.
    SHR(32, R(vReg), Imm8(3));
    LEA(32, EAX, MScaled(bufwReg, SCALE_4, 0));
    MUL(32, R(vReg));
    ADD(64, R(tempReg1), R(EAX));
 
    // Last and possible also least, the horizontal offset inside the tile.
    AND(32, R(uReg), Imm8(31));
    SHR(32, R(uReg), Imm8(1));
    MOV(8, R(resultReg), MRegSum(tempReg1, uReg));
    FixupBranch skipNonZero = J_CC(CC_NC);
    // If the horizontal offset was odd, take the upper 4.
    SHR(8, R(resultReg), Imm8(4));
    SetJumpTarget(skipNonZero);
    // Zero out the rest of the bits.
    AND(32, R(resultReg), Imm8(0x0F));
 
    return true;
}

示例7: main

    add(1,2);
    add(1,2);
    PRINTMAX(12, 13);
    PRINTMAX(12, 13);
    printf("%d\n",MAXOFNUMBER(100, 200));
    
    printf("*******************\n");
    double sum = ADD(1.1, 2);//预处理 阶段 就会换成 1+2
    printf("sum = %f\n",sum);
    
    printf("%d\n",ADD(1, 2)*ADD(2, 3));//8 //1+2*2+3
    printf("%d\n",ADD2(1, 2)*ADD2(2, 3));//(1+2)*(2+3)
    
    printf("%d\n",MUL(3-1, 5-2));//(3-1*5-2)
    printf("%d\n",MUL2(3-1, 5-2));//((3-1)*(5-2))
    
    
    printf("*******************\n");
    printf(kPath);
    double r = 2.0;
    double s = PI*r*r;
    double c = 2*PI*r;
    printf("s = %f c= %f\n",s,c);
    return 0;
}

示例8: br_i32_mulacc

void
br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b)
{
    size_t alen, blen, u;
 
    alen = (a[0] + 31) >> 5;
    blen = (b[0] + 31) >> 5;
    d[0] = a[0] + b[0];
    for (u = 0; u < blen; u ++) {
        uint32_t f;
        size_t v;
        uint64_t cc;
 
        f = b[1 + u];
        cc = 0;
        for (v = 0; v < alen; v ++) {
            uint64_t z;
 
            z = (uint64_t)d[1 + u + v] + MUL(f, a[1 + v]) + cc;
            cc = z >> 32;
            d[1 + u + v] = (uint32_t)z;
        }
        d[1 + u + alen] = (uint32_t)cc;
    }
}

示例9: gradMagNorm

void gradMagNorm( float *M, float *S, int h, int w, float norm ) {
  __m128 *_M, *_S, _norm; int i=0, n=h*w, n4=n/4;
  _S = (__m128*) S; _M = (__m128*) M; _norm = SET(norm);
  bool sse = !(size_t(M)&15) && !(size_t(S)&15);
  if(sse) for(; i<n4; i++) { *_M=MUL(*_M,RCP(ADD(*_S++,_norm))); _M++; }
  if(sse) i*=4; for(; i<n; i++) M[i] /= (S[i] + norm);
}

示例10: CDD

{
    long long int res;
    
    res=firstDigit*MUL(digitsLeft,NDigits-1);
    if(NDigits==1) //base case
    {
        #ifdef debug
    printf("\nCDD ( %d,%s,%d,%d ) returning %lld",firstDigit,number,digitsLeft,NDigits,res);
    #endif
    
        return res+1;
    }
    if(number[1]=='0'||number[1]=='1')
    {
        firstDigit=0;
    }
    else if(number[1]<number[0])
    {
        firstDigit=number[1]-48+1;
        }
    else
    {
            firstDigit=number[1]-48;
    
    }
    res+=CDD(firstDigit,number+1,digitsLeft-1,NDigits-1);
    #ifdef debug
    printf("\nCDD ( %d,%s,%d,%d ) returning %lld",firstDigit,number,digitsLeft,NDigits,res);
    #endif
    return res;
}

示例11: assert

{
#ifndef NDEBUG
    assert(node->type == NT_BINARY_EXPR);
#endif
    BinaryExpr *e = (BinaryExpr *)node;
#ifdef LOG_INTERP
    logInterpPrefix(parser);
    rawlog("binaryExprInterp\n");
    ((Parser *)parser)->interpDepth++;
#endif
    assert(e->lhs && e->rhs);
    Value *lhs = e->lhs->interp(e->lhs, parser);
    Value *rhs = e->rhs->interp(e->rhs, parser);
    switch (e->op) {
    case TK_ADD: e->value = ADD(lhs, rhs, e->value); break; /* + */
    case TK_SUB: e->value = SUB(lhs, rhs, e->value); break; /* - */
    case TK_MUL: e->value = MUL(lhs, rhs, e->value); break; /* * */
    case TK_DIV: e->value = DIV(lhs, rhs, e->value); break; /* / */
    default:
        assert(0);
        break;
    }
#ifdef LOG_INTERP
    logInterpPrefix(parser);
    rawlog("%s\n", token2str(e->op));
    ((Parser *)parser)->interpDepth--;
#endif
    return e->value;
}

示例12: main

    int x = 0;
    int y = 0;
    x = readInt();
    y = readInt();
    printf("求和结果是%d\n", MUL(x,y));
    return 0;
}

示例13: VECT

{
    Point ca = VECT(points[0], points[1]);
    Point cd = VECT(points[0], point);
    Point ab = VECT(points[1], points[2]);
    Point ad = VECT(points[1], point);
    Point bc = VECT(points[2], points[0]);
    Point bd = VECT(points[2], point);
 
    int mul1 = MUL(ca, cd);
    int mul2 = MUL(ab, ad);
    int mul3 = MUL(bc, bd);
 
    return ((SGN(mul1) == SGN(mul2)) &&
            (SGN(mul2) == SGN(mul3)) &&
            (SGN(mul3) == SGN(mul1)));
}

示例14: SET

// gradientMex('gradientMagNorm',M,S,normConst);
// normalize gradient magnitude at each location (uses sse)
void GradientMagnitudeChannel::gradMagNorm(float *M, float *S, int h, int w) {
  float norm = normalizationConstant;
  __m128 *_M, *_S, _norm; int i=0, n=h*w, n4=n/4;
  _S = (__m128*) S; _M = (__m128*) M; _norm = SET(norm);
  bool sse = !(size_t(M)&15) && !(size_t(S)&15);
  if(sse) { for(; i<n4; i++) *_M++=MUL(*_M,RCP(ADD(*_S++,_norm))); i*=4; }
  for(; i<n; i++) M[i] /= (S[i] + norm);
}

示例15: gradQuantize

void gradQuantize( float *O, float *M, int *O0, int *O1, float *M0, float *M1,
  int nb, int n, float norm, int nOrients, bool full, bool interpolate )
{
  // assumes all *OUTPUT* matrices are 4-byte aligned
  int i, o0, o1; float o, od, m;
  __m128i _o0, _o1, *_O0, *_O1; __m128 _o, _od, _m, *_M0, *_M1;
  // define useful constants
  const float oMult=(float)nOrients/(full?2*PI:PI); const int oMax=nOrients*nb;
  const __m128 _norm=SET(norm), _oMult=SET(oMult), _nbf=SET((float)nb);
  const __m128i _oMax=SET(oMax), _nb=SET(nb);
  // perform the majority of the work with sse
  _O0=(__m128i*) O0; _O1=(__m128i*) O1; _M0=(__m128*) M0; _M1=(__m128*) M1;
  if( interpolate ) for( i=0; i<=n-4; i+=4 ) {
    _o=MUL(LDu(O[i]),_oMult); _o0=CVT(_o); _od=SUB(_o,CVT(_o0));
    _o0=CVT(MUL(CVT(_o0),_nbf)); _o0=AND(CMPGT(_oMax,_o0),_o0); *_O0++=_o0;
    _o1=ADD(_o0,_nb); _o1=AND(CMPGT(_oMax,_o1),_o1); *_O1++=_o1;
    _m=MUL(LDu(M[i]),_norm); *_M1=MUL(_od,_m); *_M0++=SUB(_m,*_M1); _M1++;
  } else for( i=0; i<=n-4; i+=4 ) {
    _o=MUL(LDu(O[i]),_oMult); _o0=CVT(ADD(_o,SET(.5f)));
    _o0=CVT(MUL(CVT(_o0),_nbf)); _o0=AND(CMPGT(_oMax,_o0),_o0); *_O0++=_o0;
    *_M0++=MUL(LDu(M[i]),_norm); *_M1++=SET(0.f); *_O1++=SET(0);
  }
  // compute trailing locations without sse
  if( interpolate ) for(; i<n; i++ ) {
    o=O[i]*oMult; o0=(int) o; od=o-o0;
    o0*=nb; if(o0>=oMax) o0=0; O0[i]=o0;
    o1=o0+nb; if(o1==oMax) o1=0; O1[i]=o1;
    m=M[i]*norm; M1[i]=od*m; M0[i]=m-M1[i];
  } else for(; i<n; i++ ) {
    o=O[i]*oMult; o0=(int) (o+.5f);
    o0*=nb; if(o0>=oMax) o0=0; O0[i]=o0;
    M0[i]=M[i]*norm; M1[i]=0; O1[i]=0;
  }
}

 

 

参考文献链接

https://baijiahao.baidu.com/s?id=1703579021234485096&wfr=spider&for=pc

https://vimsky.com/examples/detail/cpp-ex-----MUL-function.html

https://github.com/joelgallant/skcf

https://github.com/3arbouch/PersonDetection

https://github.com/GodZza/contours

https://github.com/Kalamatee/mesa

https://github.com/DirectFB/mesa

https://github.com/Orphis/ppsspp

https://github.com/WZLpq/XuanIsMe-iOS-Video

https://github.com/Alcaro/Arlib

https://github.com/3arbouch/PersonDetection

https://github.com/Achal-Aggarwal/entire-src

https://github.com/wfwt/jszb

https://github.com/soplist/study-c-cpp

https://github.com/sumboid/qt-problems

https://github.com/gustavofuhr/opencv_dollar_detector

https://github.com/3arbouch/PersonDetection

标签:LLVM,int,i32,IR,C++,MUL,o0
From: https://www.cnblogs.com/wujianming-110117/p/17032060.html

相关文章

  • C/C++学生信息管理系统[2023-01-06]
    C/C++学生信息管理系统[2023-01-06]题目6学生信息管理系统(任选)本系统要求设计一个学生信息管理系统,能够进行学生信息的录入、查找,要求考虑查找效率。本题目要求采用......
  • Virtualbox-win10怎么实现 host-VM 拖拽、共享粘贴板功能?
    在Virtualbox点击“安装增强功能”后,VBOX-win10并不会像VBOX-ubuntu一样自动安装增强工具,而是要打开“此电脑”,随后在驱动处找到VirtualboxGuestAddition,点进去,执行VBo......
  • c++ 指针与引用
    引用很易与指针混淆,它们之间有三个主要的不同:不存在空引用。引用必须连接到一块合法的内存。一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候......
  • CF1779D Boris and His Amazing Haircut 题解
    可能更好的阅读体验题目传送门题目翻译题目解析如果有\(a_i<b_i\)直接输出NO。我们发现:如果\(b_l=b_r=x\)并且所有的\(l\lei\ler\)都有\(b_i\lex\)那么......
  • 《Quantifying the effects of environment and population diversity in multi-agent
    量化多智能体强化学习中环境和种群多样性的影响总结:在多种实验环境下评估多智能体强化学习受到环境多样性以及智能体多样性的影响,主要是泛化能力实验过程主要是通过改......
  • 数独游戏c++
    问题I:数独游戏时间限制:1.000Sec内存限制:128MB题目描述给你一个N×N的表格(3<N<10),在表格中事先已经填入了一部分的数字,现在请你的表格中空余的格子里填入1~N范围......
  • Dijkstra(迪杰斯特拉)算法C++实现&讲解
    Dijkstra迪杰斯特拉算法及C++实现Dijkstra算法是典型的最短路径路由算法,用来计算一个节点到其他所有节点的最短路径。算法的基本思想和流程是:1.初始化出发点到其它各点的......
  • Shiro-721反序列化漏洞
    漏洞名称Shiro-721(ApacheShiroPaddingOracleAttack)反序列化利用条件ApacheShiro<1.4.2漏洞原理ApacheShirocookie中使用AES-128-CBC模式加密的rememberMe字......
  • Kali 工具系列【3】kali Firefox浏览器下安装一些常用的渗透测试插件
    怎么做……Firefox是一个非常灵活的浏览器,非常适合用来web渗透测试,并且他默认安装在KaliLinux中。我们需要稍微定制一下,可以使用以下步骤:1. 打开Firefox,进入菜单中的附加......
  • 用批处理写了一个开启adbwireless无线调试的dos命令
    @echo"情天无奈今生薄,绿酒酩酊一日醉。"@echo"================================"@echo"********@mengtianwxs**********"@echo"================================"@ech......