authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-10-17 13:11:10+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-29 14:28:39-07:00
log1ac512df70465629d1e80ff02be51c121c6f4c07
tree43383b496614c246dd2c38544493e9ee2368c7a6
parent8f1408578cb255fbbdc555d746b25cefb331105e

stage1: Let LLVM legalize the overflowing ops on vectors

LLVM is smart enough to produce tight overflow checking sequences. On x86_64 a simple v4u32 addition is turned from: ``` c5 e9 d4 d4 vpaddq %xmm4, %xmm2, %xmm2 c5 f1 d4 cb vpaddq %xmm3, %xmm1, %xmm1 c5 f8 28 e9 vmovaps %xmm1, %xmm5 c4 e3 55 18 ea 01 vinsertf128 $1, %xmm2, %ymm5, %ymm5 c5 f0 c6 da 88 vshufps $136, %xmm2, %xmm1, %xmm3 c5 c8 57 f6 vxorps %xmm6, %xmm6, %xmm6 c4 e3 55 0c ee aa vblendps $170, %ymm6, %ymm5, %ymm5 c4 e3 7d 19 ec 01 vextractf128 $1, %ymm5, %xmm4 c4 e2 69 29 d4 vpcmpeqq %xmm4, %xmm2, %xmm2 c5 e9 ef d0 vpxor %xmm0, %xmm2, %xmm2 c4 e2 71 29 cd vpcmpeqq %xmm5, %xmm1, %xmm1 c5 f1 ef c0 vpxor %xmm0, %xmm1, %xmm0 c5 f9 6b c2 vpackssdw %xmm2, %xmm0, %xmm0 c5 f8 50 c0 vmovmskps %xmm0, %eax 84 c0 testb %al, %al ``` into: ``` c5 f9 fe c9 vpaddd %xmm1, %xmm0, %xmm1 c4 e2 71 3f c0 vpmaxud %xmm0, %xmm1, %xmm0 c5 f1 76 c0 vpcmpeqd %xmm0, %xmm1, %xmm0 c5 f8 50 c0 vmovmskps %xmm0, %eax 34 0f xorb $15, %al 0f 95 c1 setne %cl f6 c1 01 testb $1, %cl ```

1 files changed, 9 insertions(+), 28 deletions(-)

src/stage1/codegen.cpp+9-28
...@@ -1593,35 +1593,16 @@ static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub,...@@ -1593,35 +1593,16 @@ static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub,
1593static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op,1593static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op,
1594 LLVMValueRef val1, LLVMValueRef val2)1594 LLVMValueRef val1, LLVMValueRef val2)
1595{1595{
1596 LLVMValueRef overflow_bit;1596 LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op);
1597 LLVMValueRef result;1597 LLVMValueRef params[] = {
15981598 val1,
1599 val2,
1600 };
1601 LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
1602 LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
1603 LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
1599 if (operand_type->id == ZigTypeIdVector) {1604 if (operand_type->id == ZigTypeIdVector) {
1600 ZigType *int_type = operand_type->data.vector.elem_type;1605 overflow_bit = ZigLLVMBuildOrReduce(g->builder, overflow_bit);
1601 assert(int_type->id == ZigTypeIdInt);
1602 LLVMTypeRef one_more_bit_int = LLVMIntType(int_type->data.integral.bit_count + 1);
1603 LLVMTypeRef one_more_bit_int_vector = LLVMVectorType(one_more_bit_int, operand_type->data.vector.len);
1604 const auto buildExtFn = int_type->data.integral.is_signed ? LLVMBuildSExt : LLVMBuildZExt;
1605 LLVMValueRef extended1 = buildExtFn(g->builder, val1, one_more_bit_int_vector, "");
1606 LLVMValueRef extended2 = buildExtFn(g->builder, val2, one_more_bit_int_vector, "");
1607 LLVMValueRef extended_result = wrap_op[op](g->builder, extended1, extended2, "");
1608 result = LLVMBuildTrunc(g->builder, extended_result, get_llvm_type(g, operand_type), "");
1609
1610 LLVMValueRef re_extended_result = buildExtFn(g->builder, result, one_more_bit_int_vector, "");
1611 LLVMValueRef overflow_vector = LLVMBuildICmp(g->builder, LLVMIntNE, extended_result, re_extended_result, "");
1612 LLVMTypeRef bitcast_int_type = LLVMIntType(operand_type->data.vector.len);
1613 LLVMValueRef bitcasted_overflow = LLVMBuildBitCast(g->builder, overflow_vector, bitcast_int_type, "");
1614 LLVMValueRef zero = LLVMConstNull(bitcast_int_type);
1615 overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, bitcasted_overflow, zero, "");
1616 } else {
1617 LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op);
1618 LLVMValueRef params[] = {
1619 val1,
1620 val2,
1621 };
1622 LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
1623 result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
1624 overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
1625 }1606 }
16261607
1627 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");1608 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");