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