1 // Copyright 2020, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #include "examples.h"
28
29 using namespace vixl;
30 using namespace vixl::aarch64;
31
32 #define __ masm->
33
34 // size_t sve_strlen(const char* str);
GenerateSVEStrlen(MacroAssembler * masm)35 void GenerateSVEStrlen(MacroAssembler* masm) {
36 // We will accumulate the length as we load each chunk.
37 Register len = x1;
38 __ Mov(len, 0);
39
40 // We want to load as much as we can on each iteration, so set up an all-true
41 // predicate for that purpose.
42 PRegister all_true = p0;
43 __ Ptrue(all_true.VnB());
44
45 Label loop;
46 __ Bind(&loop);
47 // FFR is cumulative, so reset it to all-true for each iteration.
48 __ Setffr();
49
50 // Load as many characters as we can from &str[len]. We have to use a NF or FF
51 // load, because we don't know how long the string is. An FF load is a good
52 // choice, because we know that we will see at least a NULL termination, even
53 // for an empty string.
54 __ Ldff1b(z0.VnB(), all_true.Zeroing(), SVEMemOperand(x0, len));
55 // For example, if str = "Test string.", and we load every byte:
56 // z0.b: \0 . g n i r t s t s e T
57
58 // FFR now represents the number of bytes that we actually loaded, so use it
59 // to predicate the data processing instructions.
60 __ Rdffr(p1.VnB());
61
62 // Find the NULL termination (if there is one), and set the flags.
63 __ Cmpeq(p2.VnB(), p1.Zeroing(), z0.VnB(), 0);
64 // p2.b: 1 0 0 0 0 0 0 0 0 0 0 0 0
65
66 // Activate every lane up to (but not including) the NULL termination. If we
67 // found no NULL termination, this activates every lane, and indicates that we
68 // have to load another vector of characters. Lanes activated in this way
69 // represent string characters that we need to count.
70 __ Brkb(p1.VnB(), p1.Zeroing(), p2.VnB());
71 // p1.b: 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
72
73 // Count the active lanes, and add them to the length count.
74 __ Incp(len, p1.VnB());
75
76 // Loop until `cmpeq` finds a NULL termination.
77 __ B(sve_none, &loop);
78
79 // Put the length in the AAPCS64 return register.
80 __ Mov(x0, len);
81 __ Ret();
82 }
83
84 #ifndef TEST_EXAMPLES
85 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
main(void)86 int main(void) {
87 MacroAssembler masm;
88 Decoder decoder;
89 Simulator simulator(&decoder);
90
91 // We're running on the simulator, so we can assume that SVE is present.
92 masm.GetCPUFeatures()->Combine(CPUFeatures::kSVE);
93
94 // Generate the code for the example function.
95 Label sve_strlen;
96 masm.Bind(&sve_strlen);
97 GenerateSVEStrlen(&masm);
98 masm.FinalizeCode();
99
100 const char* example_input = "This is a string of exactly 42 characters.";
101 VIXL_ASSERT(strlen(example_input) == 42);
102
103 simulator.ResetState();
104 simulator.WriteXRegister(0, reinterpret_cast<uintptr_t>(example_input));
105 simulator.RunFrom(masm.GetLabelAddress<Instruction*>(&sve_strlen));
106
107 printf("strlen(\"%s\") == %" PRIu64 "\n",
108 example_input,
109 simulator.ReadXRegister(0));
110
111 return 0;
112 }
113 #else
114 // Without the simulator there is nothing to test.
main(void)115 int main(void) { return 0; }
116 #endif // VIXL_INCLUDE_SIMULATOR_AARCH64
117 #endif // TEST_EXAMPLES
118