authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-04 18:45:52+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-04 18:45:52+02:00
log4bf093f1a00e481d923452955ab9c394c30b8694
treea5076c7a6e023e5cfd2052c94a0b459371aab362
parent389d1177a57a442b7814d9fdede2a088c614b69d

compiler-rt: Better selection of __clzsi implementation

To be honest all this detection logic is starting to become a real PITA, the ARM32 version can be possibly removed as the generic version optimizes pretty well...

2 files changed, 22 insertions(+), 7 deletions(-)

lib/std/special/compiler_rt/clzsi2.zig+20-7
...@@ -26,6 +26,8 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 {...@@ -26,6 +26,8 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 {
26}26}
2727
28fn __clzsi2_thumb1() callconv(.Naked) void {28fn __clzsi2_thumb1() callconv(.Naked) void {
29 @setRuntimeSafety(false);
30
29 // Similar to the generic version with the last two rounds replaced by a LUT31 // Similar to the generic version with the last two rounds replaced by a LUT
30 asm volatile (32 asm volatile (
31 \\ movs r1, #3233 \\ movs r1, #32
...@@ -58,6 +60,8 @@ fn __clzsi2_thumb1() callconv(.Naked) void {...@@ -58,6 +60,8 @@ fn __clzsi2_thumb1() callconv(.Naked) void {
58}60}
5961
60fn __clzsi2_arm32() callconv(.Naked) void {62fn __clzsi2_arm32() callconv(.Naked) void {
63 @setRuntimeSafety(false);
64
61 asm volatile (65 asm volatile (
62 \\ // Assumption: n != 066 \\ // Assumption: n != 0
63 \\ // r0: n67 \\ // r0: n
...@@ -104,13 +108,22 @@ fn __clzsi2_arm32() callconv(.Naked) void {...@@ -104,13 +108,22 @@ fn __clzsi2_arm32() callconv(.Naked) void {
104 unreachable;108 unreachable;
105}109}
106110
107pub const __clzsi2 = switch (std.Target.current.cpu.arch) {111pub const __clzsi2 = impl: {
108 .arm, .armeb => if (std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm))112 switch (std.Target.current.cpu.arch) {
109 __clzsi2_thumb1113 .arm, .armeb, .thumb, .thumbeb => {
110 else114 const use_thumb1 =
111 __clzsi2_arm32,115 (std.Target.current.cpu.arch.isThumb() or
112 .thumb, .thumbeb => __clzsi2_thumb1,116 std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm)) and
113 else => __clzsi2_generic,117 !std.Target.arm.featureSetHas(std.Target.current.cpu.features, .thumb2);
118
119 if (use_thumb1) break :impl __clzsi2_thumb1
120 // From here on we're either targeting Thumb2 or ARM.
121 else if (!std.Target.current.cpu.arch.isThumb()) break :impl __clzsi2_arm32
122 // Use the generic implementation otherwise.
123 else break :impl __clzsi2_generic;
124 },
125 else => break :impl __clzsi2_generic,
126 }
114};127};
115128
116test "test clzsi2" {129test "test clzsi2" {
lib/std/special/compiler_rt/clzsi2_test.zig+2
...@@ -7,6 +7,8 @@ const clzsi2 = @import("clzsi2.zig");...@@ -7,6 +7,8 @@ const clzsi2 = @import("clzsi2.zig");
7const testing = @import("std").testing;7const testing = @import("std").testing;
88
9fn test__clzsi2(a: u32, expected: i32) void {9fn test__clzsi2(a: u32, expected: i32) void {
10 // XXX At high optimization levels this test may be horribly miscompiled if
11 // one of the naked implementations is selected.
10 var nakedClzsi2 = clzsi2.__clzsi2;12 var nakedClzsi2 = clzsi2.__clzsi2;
11 var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2);13 var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2);
12 var x = @bitCast(i32, a);14 var x = @bitCast(i32, a);