Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workaround fixuint causing compiler segfault with u1 #1817

Conversation

Projects
None yet
3 participants
@winksaville
Copy link
Contributor

winksaville commented Dec 4, 2018

Add fixuint_test.zig to test.

Workaround fixuint causing compiler segfault with u1
Add fixuint_test.zig to test.
@thejoshwolfe

This comment has been minimized.

Copy link
Member

thejoshwolfe commented Dec 5, 2018

what is fixuint

@winksaville

This comment has been minimized.

Copy link
Contributor Author

winksaville commented Dec 5, 2018

A function in compiler_rt that converts a float to an unsigned int.

@thejoshwolfe

This comment has been minimized.

Copy link
Member

thejoshwolfe commented Dec 5, 2018

So would you get this by calling@floatToInt(u1, f32(x))?

@winksaville

This comment has been minimized.

Copy link
Contributor Author

winksaville commented Dec 5, 2018

Yes and no, it depends on if the target architecture supports the conversion natively or not. Given this code:

$ cat -n floattoint.zig
     1	var result: bool = undefined;
     2	var vF32: f32 = 1;
     3	
     4	export fn floatToInt() bool {
     5	    const pResult: *volatile bool = &result;
     6	    const pvF32: *volatile f32 = &vF32;
     7	
     8	    pResult.* = @floatToInt(u1, pvF32.*) == 1;
     9	    pResult.* = @floatToInt(u1, pvF32.*) == 0;
    10	    
    11	    return pResult.*;
    12	}

$ cat -n Makefile 
     1	arch:=x86_64
     2	os:=freestanding
     3	environ:=unknown
     4	
     5	floattoint.s : floattoint.zig
     6		zig build-obj --strip --emit asm --release-fast floattoint.zig --target-arch $(arch) --target-os $(os) --target-environ $(environ)
     7	
     8	clean:
     9		rm -rf *.s *.asm *.o

On the x86_64 it's not used:

$ make arch=x86_64 -B
zig build-obj --strip --emit asm --release-fast floattoint.zig --target-arch x86_64 --target-os freestanding --target-environ unknown

$ cat -n floattoint.s
     1		.text
     2		.file	"floattoint"
     3		.globl	floatToInt
     4		.p2align	4, 0x90
     5		.type	floatToInt,@function
     6	floatToInt:
     7		cvttss2si	vF32(%rip), %eax
     8		movb	%al, result(%rip)
     9		cvttss2si	vF32(%rip), %eax
    10		xorb	$1, %al
    11		movb	%al, result(%rip)
    12		movb	result(%rip), %al
    13		retq
    14	.Lfunc_end0:
    15		.size	floatToInt, .Lfunc_end0-floatToInt
    16	
    17		.type	result,@object
    18		.local	result
    19		.comm	result,1,1
    20		.type	vF32,@object
    21		.data
    22		.p2align	2
    23	vF32:
    24		.long	1065353216
    25		.size	vF32, 4
    26	
    27	
    28		.section	".note.GNU-stack","",@progbits

But on armv5 fixuint is called indirectly via __fixunssfsi

$ make arch=armv5 -B
zig build-obj --strip --emit asm --release-fast floattoint.zig --target-arch armv5 --target-os freestanding --target-environ unknown
wink@wink-desktop:~/prgs/ziglang/zig-explore/float_to_int (master)
$ cat -n floattoint.s
     1		.text
     2		.syntax unified
     3		.eabi_attribute	67, "2.09"
     4		.eabi_attribute	6, 3
     5		.eabi_attribute	8, 1
     6		.eabi_attribute	9, 1
     7		.eabi_attribute	34, 1
     8		.eabi_attribute	15, 1
     9		.eabi_attribute	16, 1
    10		.eabi_attribute	17, 2
    11		.eabi_attribute	20, 1
    12		.eabi_attribute	21, 1
    13		.eabi_attribute	23, 3
    14		.eabi_attribute	24, 1
    15		.eabi_attribute	25, 1
    16		.eabi_attribute	38, 1
    17		.eabi_attribute	14, 0
    18		.file	"floattoint"
    19		.globl	floatToInt
    20		.p2align	2
    21		.type	floatToInt,%function
    22		.code	32
    23	floatToInt:
    24		.fnstart
    25		push	{r4, lr}
    26		ldr	r0, .LCPI0_0
    27	.LPC0_0:
    28		ldr	r0, [pc, r0]
    29		bl	__fixunssfsi
    30		ldr	r4, .LCPI0_1
    31	.LPC0_1:
    32		add	r4, pc, r4
    33		strb	r0, [r4]
    34		ldr	r0, .LCPI0_2
    35	.LPC0_2:
    36		ldr	r0, [pc, r0]
    37		bl	__fixunssfsi
    38		eor	r0, r0, #1
    39		strb	r0, [r4]
    40		ldrb	r0, [r4]
    41		pop	{r4, pc}
    42		.p2align	2
    43	.LCPI0_0:
    44		.long	vF32-(.LPC0_0+8)
    45	.LCPI0_1:
    46		.long	result-(.LPC0_1+8)
    47	.LCPI0_2:
    48		.long	vF32-(.LPC0_2+8)
    49	.Lfunc_end0:
    50		.size	floatToInt, .Lfunc_end0-floatToInt
    51		.cantunwind
    52		.fnend
    53	
    54		.type	result,%object
    55		.local	result
    56		.comm	result,1,1
    57		.type	vF32,%object
    58		.data
    59		.p2align	2
    60	vF32:
    61		.long	1065353216
    62		.size	vF32, 4
    63	
    64	
    65		.section	".note.GNU-stack","",%progbits

Here is __fixunssfsi:

$ cat -n fixunssfsi.zig
     1	const fixuint = @import("fixuint.zig").fixuint;
     2	const builtin = @import("builtin");
     3	
     4	pub extern fn __fixunssfsi(a: f32) u32 {
     5	    @setRuntimeSafety(builtin.is_test);
     6	    return fixuint(f32, u32, a);
     7	}
     8	
     9	test "import fixunssfsi" {
    10	    _ = @import("fixunssfsi_test.zig");
    11	}
@thejoshwolfe

This comment has been minimized.

Copy link
Member

thejoshwolfe commented Dec 5, 2018

so what of you do @floatToInt(u2, pvF32.*)?

@winksaville

This comment has been minimized.

Copy link
Contributor Author

winksaville commented Dec 5, 2018

Here is u1, u2, u64, u65, u128. On x86_64 u1..u64 do not call __fixunssfti/fixuint but u65 .. u128 do:

$ cat -n floattoint.zig
     1	var result: bool = undefined;
     2	var vF32: f32 = 1;
     3	
     4	export fn floatToInt() bool {
     5	    const pResult: *volatile bool = &result;
     6	    const pvF32: *volatile f32 = &vF32;
     7	
     8	    pResult.* = @floatToInt(u1, pvF32.*) == 1;
     9	    pResult.* = @floatToInt(u2, pvF32.*) == 1;
    10      pResult.* = @floatToInt(u64, pvF32.*) == 1;
    11      pResult.* = @floatToInt(u65, pvF32.*) == 1;
    12      pResult.* = @floatToInt(u128, pvF32.*) == 1;
    13	
    14      return pResult.*;
    15  }

$ make arch=x86_64 -B
zig build-obj --strip --emit asm --release-fast floattoint.zig --target-arch x86_64 --target-os freestanding --target-environ unknown

$ cat -n floattoint.s
     1		.text
     2		.file	"floattoint"
     3		.section	.rodata.cst4,"aM",@progbits,4
     4		.p2align	2
     5	.LCPI0_0:
     6		.long	1593835520
     7		.text
     8		.globl	floatToInt
     9		.p2align	4, 0x90
    10		.type	floatToInt,@function
    11	floatToInt:
    12		pushq	%rax
    13		cvttss2si	vF32(%rip), %eax
    14		movb	%al, result(%rip)
    15		cvttss2si	vF32(%rip), %eax
    16		cmpb	$1, %al
    17		sete	result(%rip)
    18		movss	vF32(%rip), %xmm0
    19		movss	.LCPI0_0(%rip), %xmm1
    20		movaps	%xmm0, %xmm2
    21		subss	%xmm1, %xmm2
    22		cvttss2si	%xmm2, %rax
    23		movabsq	$-9223372036854775808, %rcx
    24		xorq	%rax, %rcx
    25		cvttss2si	%xmm0, %rax
    26		ucomiss	%xmm0, %xmm1
    27		cmovbeq	%rcx, %rax
    28		cmpq	$1, %rax
    29		sete	result(%rip)
    30		movss	vF32(%rip), %xmm0
    31		callq	__fixunssfti@PLT
    32		xorq	$1, %rax
    33		orq	%rdx, %rax
    34		sete	result(%rip)
    35		movss	vF32(%rip), %xmm0
    36		callq	__fixunssfti@PLT
    37		movq	%rdx, %xmm0
    38		movq	%rax, %xmm1
    39		punpcklqdq	%xmm0, %xmm1
    40		movl	$1, %eax
    41		movq	%rax, %xmm0
    42		pcmpeqb	%xmm1, %xmm0
    43		pmovmskb	%xmm0, %eax
    44		cmpl	$65535, %eax
    45		sete	result(%rip)
    46		movb	result(%rip), %al
    47		popq	%rcx
    48		retq
    49	.Lfunc_end0:
    50		.size	floatToInt, .Lfunc_end0-floatToInt
    51	
    52		.type	result,@object
    53		.local	result
    54		.comm	result,1,1
    55		.type	vF32,@object
    56		.data
    57		.p2align	2
    58	vF32:
    59		.long	1065353216
    60		.size	vF32, 4
    61	
    62	
    63		.section	".note.GNU-stack","",@progbits

On armv5 they all call __fixunssfti/fixuint:

$ make arch=armv5 -B
zig build-obj --strip --emit asm --release-fast floattoint.zig --target-arch armv5 --target-os freestanding --target-environ unknown

$ cat -n floattoint.s
     1		.text
     2		.syntax unified
     3		.eabi_attribute	67, "2.09"
     4		.eabi_attribute	6, 3
     5		.eabi_attribute	8, 1
     6		.eabi_attribute	9, 1
     7		.eabi_attribute	34, 1
     8		.eabi_attribute	15, 1
     9		.eabi_attribute	16, 1
    10		.eabi_attribute	17, 2
    11		.eabi_attribute	20, 1
    12		.eabi_attribute	21, 1
    13		.eabi_attribute	23, 3
    14		.eabi_attribute	24, 1
    15		.eabi_attribute	25, 1
    16		.eabi_attribute	38, 1
    17		.eabi_attribute	14, 0
    18		.file	"floattoint"
    19		.globl	floatToInt
    20		.p2align	2
    21		.type	floatToInt,%function
    22		.code	32
    23	floatToInt:
    24		.fnstart
    25		push	{r4, lr}
    26		ldr	r0, .LCPI0_0
    27	.LPC0_0:
    28		ldr	r0, [pc, r0]
    29		bl	__fixunssfsi
    30		ldr	r4, .LCPI0_1
    31	.LPC0_1:
    32		add	r4, pc, r4
    33		strb	r0, [r4]
    34		ldr	r0, .LCPI0_2
    35	.LPC0_2:
    36		ldr	r0, [pc, r0]
    37		bl	__fixunssfsi
    38		sub	r0, r0, #1
    39		clz	r0, r0
    40		lsr	r0, r0, #5
    41		strb	r0, [r4]
    42		ldr	r0, .LCPI0_3
    43	.LPC0_3:
    44		ldr	r0, [pc, r0]
    45		bl	__fixunssfdi
    46		eor	r0, r0, #1
    47		orr	r0, r0, r1
    48		clz	r0, r0
    49		lsr	r0, r0, #5
    50		strb	r0, [r4]
    51		ldr	r0, .LCPI0_4
    52	.LPC0_4:
    53		ldr	r0, [pc, r0]
    54		bl	__fixunssfti
    55		eor	r0, r0, #1
    56		orr	r0, r0, r2
    57		orr	r0, r0, r1
    58		clz	r0, r0
    59		lsr	r0, r0, #5
    60		strb	r0, [r4]
    61		ldr	r0, .LCPI0_5
    62	.LPC0_5:
    63		ldr	r0, [pc, r0]
    64		bl	__fixunssfti
    65		eor	r0, r0, #1
    66		orr	r1, r1, r3
    67		orr	r0, r0, r2
    68		orr	r0, r0, r1
    69		clz	r0, r0
    70		lsr	r0, r0, #5
    71		strb	r0, [r4]
    72		ldrb	r0, [r4]
    73		pop	{r4, pc}
    74		.p2align	2
    75	.LCPI0_0:
    76		.long	vF32-(.LPC0_0+8)
    77	.LCPI0_1:
    78		.long	result-(.LPC0_1+8)
    79	.LCPI0_2:
    80		.long	vF32-(.LPC0_2+8)
    81	.LCPI0_3:
    82		.long	vF32-(.LPC0_3+8)
    83	.LCPI0_4:
    84		.long	vF32-(.LPC0_4+8)
    85	.LCPI0_5:
    86		.long	vF32-(.LPC0_5+8)
    87	.Lfunc_end0:
    88		.size	floatToInt, .Lfunc_end0-floatToInt
    89		.cantunwind
    90		.fnend
    91	
    92		.type	result,%object
    93		.local	result
    94		.comm	result,1,1
    95		.type	vF32,%object
    96		.data
    97		.p2align	2
    98	vF32:
    99		.long	1065353216
   100		.size	vF32, 4
   101	
   102	
   103		.section	".note.GNU-stack","",%progbits
@thejoshwolfe

This comment has been minimized.

Copy link
Member

thejoshwolfe commented Dec 6, 2018

i guess I'm confused why u1 needs special case handling and not u2.

@winksaville

This comment has been minimized.

Copy link
Contributor Author

winksaville commented Dec 6, 2018

I don't know but as has been discussed 0 and 1 bit values can be tricky. For instance we can't print i1 although u1 works:

$ cat print_1bit_ints.zig 
const warn = @import("std").debug.warn;

test "print i1" {
    var v1: i1 = -1;
    warn("v1={}\n", v1);
}
wink@wink-desktop:~/prgs/ziglang/zig-explore/float_to_int (master)
$ zig test print_1bit_ints.zig 
/home/wink/opt/lib/zig/std/fmt/index.zig:704:52: error: integer value 1 cannot be implicitly casted to type 'i1'
        const new_value = @intCast(uint, -(value + 1)) + 1;
                                                   ^
/home/wink/opt/lib/zig/std/fmt/index.zig:685:31: note: called from here
        return formatIntSigned(value, base, uppercase, width, context, Errors, output);
                              ^
/home/wink/opt/lib/zig/std/fmt/index.zig:321:21: note: called from here
    return formatInt(value, radix, uppercase, width, context, Errors, output);
                    ^
/home/wink/opt/lib/zig/std/fmt/index.zig:274:52: note: called from here
        builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
                                                   ^
/home/wink/opt/lib/zig/std/fmt/index.zig:121:31: note: called from here
            return formatValue(value, fmt, context, Errors, output);
                              ^
/home/wink/opt/lib/zig/std/fmt/index.zig:54:35: note: called from here
                    try formatType(args[next_arg], fmt[0..0], context, Errors, output);
                                  ^
/home/wink/opt/lib/zig/std/io.zig:211:34: note: called from here
            return std.fmt.format(self, Error, self.writeFn, format, args);
                                 ^
/home/wink/opt/lib/zig/std/debug/index.zig:47:17: note: called from here
    stderr.print(fmt, args) catch return;
                ^
/home/wink/prgs/ziglang/zig-explore/float_to_int/print_1bit_ints.zig:5:9: note: called from here
    warn("v1={}\n", v1);
        ^
@thejoshwolfe

This comment has been minimized.

Copy link
Member

thejoshwolfe commented Dec 8, 2018

Ha! That's a bug with the std.fmt code.

Did you track down what the segfault was in the compiler that this works around? Maybe there's a better solution than hardcoding u1 handling.

@winksaville

This comment has been minimized.

Copy link
Contributor Author

winksaville commented Dec 8, 2018

No, I'm busy doing other stuff and figured an expert could solve it more quickly then I.

@Tom-Phinney

This comment has been minimized.

Copy link

Tom-Phinney commented Dec 23, 2018

@andrewrk andrewrk closed this in f330eeb Feb 7, 2019

winksaville added a commit to winksaville/zig-explore that referenced this pull request Feb 8, 2019

Tested with "latest" changes to Master.
This includes the specific fix for issue 1817[1]

[1]: ziglang/zig#1817
@winksaville

This comment has been minimized.

Copy link
Contributor Author

winksaville commented Feb 8, 2019

@andrewrk, the code I had is now working with this fix. TXS!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.