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
32namespace vixl {
33
34namespace aarch32 {
35
36bool 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
44void 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
55static bool Is16BitEncoding(uint16_t instr) {
56  return instr < (kLowestT32_32Opcode >> 16);
57}
58
59void 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
87void 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
104int 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
115int 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
126void 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
134void 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
145void 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