1 // Copyright 2017, 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 "location-aarch32.h"
28
29 #include "assembler-aarch32.h"
30 #include "macro-assembler-aarch32.h"
31
32 namespace vixl {
33
34 namespace aarch32 {
35
Needs16BitPadding(int32_t location) const36 bool Location::Needs16BitPadding(int32_t location) const {
37 if (!HasForwardReferences()) return false;
38 const ForwardRef& last_ref = GetLastForwardReference();
39 int32_t min_location_last_ref = last_ref.GetMinLocation();
40 VIXL_ASSERT(min_location_last_ref - location <= 2);
41 return (min_location_last_ref > location);
42 }
43
ResolveReferences(internal::AssemblerBase * assembler)44 void Location::ResolveReferences(internal::AssemblerBase* assembler) {
45 // Iterate over references and call EncodeLocationFor on each of them.
46 for (ForwardRefListIterator it(this); !it.Done(); it.Advance()) {
47 const ForwardRef& reference = *it.Current();
48 VIXL_ASSERT(reference.LocationIsEncodable(location_));
49 int32_t from = reference.GetLocation();
50 EncodeLocationFor(assembler, from, reference.op());
51 }
52 forward_.clear();
53 }
54
Is16BitEncoding(uint16_t instr)55 static bool Is16BitEncoding(uint16_t instr) {
56 return instr < (kLowestT32_32Opcode >> 16);
57 }
58
EncodeLocationFor(internal::AssemblerBase * assembler,int32_t from,const Location::EmitOperator * encoder)59 void Location::EncodeLocationFor(internal::AssemblerBase* assembler,
60 int32_t from,
61 const Location::EmitOperator* encoder) {
62 if (encoder->IsUsingT32()) {
63 uint16_t* instr_ptr =
64 assembler->GetBuffer()->GetOffsetAddress<uint16_t*>(from);
65 if (Is16BitEncoding(instr_ptr[0])) {
66 // The Encode methods always deals with uint32_t types so we need
67 // to explicitly cast it.
68 uint32_t instr = static_cast<uint32_t>(instr_ptr[0]);
69 instr = encoder->Encode(instr, from, this);
70 // The Encode method should not ever set the top 16 bits.
71 VIXL_ASSERT((instr & ~0xffff) == 0);
72 instr_ptr[0] = static_cast<uint16_t>(instr);
73 } else {
74 uint32_t instr =
75 instr_ptr[1] | (static_cast<uint32_t>(instr_ptr[0]) << 16);
76 instr = encoder->Encode(instr, from, this);
77 instr_ptr[0] = static_cast<uint16_t>(instr >> 16);
78 instr_ptr[1] = static_cast<uint16_t>(instr);
79 }
80 } else {
81 uint32_t* instr_ptr =
82 assembler->GetBuffer()->GetOffsetAddress<uint32_t*>(from);
83 instr_ptr[0] = encoder->Encode(instr_ptr[0], from, this);
84 }
85 }
86
AddForwardRef(int32_t instr_location,const EmitOperator & op,const ReferenceInfo * info)87 void Location::AddForwardRef(int32_t instr_location,
88 const EmitOperator& op,
89 const ReferenceInfo* info) {
90 VIXL_ASSERT(referenced_);
91 int32_t from = instr_location + (op.IsUsingT32() ? kT32PcDelta : kA32PcDelta);
92 if (info->pc_needs_aligning == ReferenceInfo::kAlignPc)
93 from = AlignDown(from, 4);
94 int32_t min_object_location = from + info->min_offset;
95 int32_t max_object_location = from + info->max_offset;
96 forward_.insert(ForwardRef(&op,
97 instr_location,
98 info->size,
99 min_object_location,
100 max_object_location,
101 info->alignment));
102 }
103
GetMaxAlignment() const104 int Location::GetMaxAlignment() const {
105 int max_alignment = GetPoolObjectAlignment();
106 for (ForwardRefListIterator it(const_cast<Location*>(this)); !it.Done();
107 it.Advance()) {
108 const ForwardRef& reference = *it.Current();
109 if (reference.GetAlignment() > max_alignment)
110 max_alignment = reference.GetAlignment();
111 }
112 return max_alignment;
113 }
114
GetMinLocation() const115 int Location::GetMinLocation() const {
116 int32_t min_location = 0;
117 for (ForwardRefListIterator it(const_cast<Location*>(this)); !it.Done();
118 it.Advance()) {
119 const ForwardRef& reference = *it.Current();
120 if (reference.GetMinLocation() > min_location)
121 min_location = reference.GetMinLocation();
122 }
123 return min_location;
124 }
125
UpdatePoolObject(PoolObject<int32_t> * object)126 void Label::UpdatePoolObject(PoolObject<int32_t>* object) {
127 VIXL_ASSERT(forward_.size() == 1);
128 const ForwardRef& reference = forward_.Front();
129 object->Update(reference.GetMinLocation(),
130 reference.GetMaxLocation(),
131 reference.GetAlignment());
132 }
133
EmitPoolObject(MacroAssemblerInterface * masm)134 void Label::EmitPoolObject(MacroAssemblerInterface* masm) {
135 MacroAssembler* macro_assembler = static_cast<MacroAssembler*>(masm);
136
137 // Add a new branch to this label.
138 macro_assembler->GetBuffer()->EnsureSpaceFor(kMaxInstructionSizeInBytes);
139 ExactAssemblyScopeWithoutPoolsCheck guard(macro_assembler,
140 kMaxInstructionSizeInBytes,
141 ExactAssemblyScope::kMaximumSize);
142 macro_assembler->b(this);
143 }
144
EmitPoolObject(MacroAssemblerInterface * masm)145 void RawLiteral::EmitPoolObject(MacroAssemblerInterface* masm) {
146 Assembler* assembler = static_cast<Assembler*>(masm->AsAssemblerBase());
147
148 assembler->GetBuffer()->EnsureSpaceFor(GetSize());
149 assembler->GetBuffer()->EmitData(GetDataAddress(), GetSize());
150 }
151 }
152 }
153