xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceAssembler.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceAssembler.cpp - Assembler base class ----------------===//
2*03ce13f7SAndroid Build Coastguard Worker // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
3*03ce13f7SAndroid Build Coastguard Worker // for details. All rights reserved. Use of this source code is governed by a
4*03ce13f7SAndroid Build Coastguard Worker // BSD-style license that can be found in the LICENSE file.
5*03ce13f7SAndroid Build Coastguard Worker //
6*03ce13f7SAndroid Build Coastguard Worker // Modified by the Subzero authors.
7*03ce13f7SAndroid Build Coastguard Worker //
8*03ce13f7SAndroid Build Coastguard Worker // This is forked from Dart revision 39313.
9*03ce13f7SAndroid Build Coastguard Worker // Please update the revision if we merge back changes from Dart.
10*03ce13f7SAndroid Build Coastguard Worker // https://code.google.com/p/dart/wiki/GettingTheSource
11*03ce13f7SAndroid Build Coastguard Worker //
12*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
13*03ce13f7SAndroid Build Coastguard Worker //
14*03ce13f7SAndroid Build Coastguard Worker //                        The Subzero Code Generator
15*03ce13f7SAndroid Build Coastguard Worker //
16*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
17*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
18*03ce13f7SAndroid Build Coastguard Worker //
19*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
20*03ce13f7SAndroid Build Coastguard Worker ///
21*03ce13f7SAndroid Build Coastguard Worker /// \file
22*03ce13f7SAndroid Build Coastguard Worker /// \brief Implements the Assembler base class.
23*03ce13f7SAndroid Build Coastguard Worker ///
24*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
25*03ce13f7SAndroid Build Coastguard Worker 
26*03ce13f7SAndroid Build Coastguard Worker #include "IceAssembler.h"
27*03ce13f7SAndroid Build Coastguard Worker 
28*03ce13f7SAndroid Build Coastguard Worker #include "IceGlobalContext.h"
29*03ce13f7SAndroid Build Coastguard Worker #include "IceOperand.h"
30*03ce13f7SAndroid Build Coastguard Worker 
31*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
32*03ce13f7SAndroid Build Coastguard Worker 
NewContents(Assembler & Assemblr,intptr_t Capacity)33*03ce13f7SAndroid Build Coastguard Worker static uintptr_t NewContents(Assembler &Assemblr, intptr_t Capacity) {
34*03ce13f7SAndroid Build Coastguard Worker   uintptr_t Result = Assemblr.allocateBytes(Capacity);
35*03ce13f7SAndroid Build Coastguard Worker   return Result;
36*03ce13f7SAndroid Build Coastguard Worker }
37*03ce13f7SAndroid Build Coastguard Worker 
linkTo(const Assembler & Asm,intptr_t Pos)38*03ce13f7SAndroid Build Coastguard Worker void Label::linkTo(const Assembler &Asm, intptr_t Pos) {
39*03ce13f7SAndroid Build Coastguard Worker   // We must not set the link until the position is absolutely known. This means
40*03ce13f7SAndroid Build Coastguard Worker   // not during the preliminary (sandboxing) pass, and not when the instruction
41*03ce13f7SAndroid Build Coastguard Worker   // needs a text fixup (hybrid iasm mode).
42*03ce13f7SAndroid Build Coastguard Worker   if (Asm.getPreliminary() || Asm.needsTextFixup())
43*03ce13f7SAndroid Build Coastguard Worker     return;
44*03ce13f7SAndroid Build Coastguard Worker   assert(!isBound());
45*03ce13f7SAndroid Build Coastguard Worker   Position = Pos + kWordSize;
46*03ce13f7SAndroid Build Coastguard Worker   assert(isLinked());
47*03ce13f7SAndroid Build Coastguard Worker }
48*03ce13f7SAndroid Build Coastguard Worker 
installFixup(AssemblerFixup * F)49*03ce13f7SAndroid Build Coastguard Worker void AssemblerBuffer::installFixup(AssemblerFixup *F) {
50*03ce13f7SAndroid Build Coastguard Worker   if (!Assemblr.getPreliminary())
51*03ce13f7SAndroid Build Coastguard Worker     Fixups.push_back(F);
52*03ce13f7SAndroid Build Coastguard Worker }
53*03ce13f7SAndroid Build Coastguard Worker 
createFixup(FixupKind Kind,const Constant * Value)54*03ce13f7SAndroid Build Coastguard Worker AssemblerFixup *AssemblerBuffer::createFixup(FixupKind Kind,
55*03ce13f7SAndroid Build Coastguard Worker                                              const Constant *Value) {
56*03ce13f7SAndroid Build Coastguard Worker   AssemblerFixup *F =
57*03ce13f7SAndroid Build Coastguard Worker       new (Assemblr.allocate<AssemblerFixup>()) AssemblerFixup();
58*03ce13f7SAndroid Build Coastguard Worker   F->set_kind(Kind);
59*03ce13f7SAndroid Build Coastguard Worker   F->set_value(Value);
60*03ce13f7SAndroid Build Coastguard Worker   installFixup(F);
61*03ce13f7SAndroid Build Coastguard Worker   return F;
62*03ce13f7SAndroid Build Coastguard Worker }
63*03ce13f7SAndroid Build Coastguard Worker 
createTextFixup(const std::string & Text,size_t BytesUsed)64*03ce13f7SAndroid Build Coastguard Worker AssemblerTextFixup *AssemblerBuffer::createTextFixup(const std::string &Text,
65*03ce13f7SAndroid Build Coastguard Worker                                                      size_t BytesUsed) {
66*03ce13f7SAndroid Build Coastguard Worker   AssemblerTextFixup *F = new (Assemblr.allocate<AssemblerTextFixup>())
67*03ce13f7SAndroid Build Coastguard Worker       AssemblerTextFixup(Text, BytesUsed);
68*03ce13f7SAndroid Build Coastguard Worker   installFixup(F);
69*03ce13f7SAndroid Build Coastguard Worker   resetNeedsTextFixup();
70*03ce13f7SAndroid Build Coastguard Worker   return F;
71*03ce13f7SAndroid Build Coastguard Worker }
72*03ce13f7SAndroid Build Coastguard Worker 
validate(AssemblerBuffer * buffer)73*03ce13f7SAndroid Build Coastguard Worker void AssemblerBuffer::EnsureCapacity::validate(AssemblerBuffer *buffer) {
74*03ce13f7SAndroid Build Coastguard Worker   // In debug mode, we save the assembler buffer along with the gap size before
75*03ce13f7SAndroid Build Coastguard Worker   // we start emitting to the buffer. This allows us to check that any single
76*03ce13f7SAndroid Build Coastguard Worker   // generated instruction doesn't overflow the limit implied by the minimum
77*03ce13f7SAndroid Build Coastguard Worker   // gap size.
78*03ce13f7SAndroid Build Coastguard Worker   Gap = computeGap();
79*03ce13f7SAndroid Build Coastguard Worker   // Make sure that extending the capacity leaves a big enough gap for any kind
80*03ce13f7SAndroid Build Coastguard Worker   // of instruction.
81*03ce13f7SAndroid Build Coastguard Worker   assert(Gap >= kMinimumGap);
82*03ce13f7SAndroid Build Coastguard Worker   // Mark the buffer as having ensured the capacity.
83*03ce13f7SAndroid Build Coastguard Worker   assert(!buffer->hasEnsuredCapacity()); // Cannot nest.
84*03ce13f7SAndroid Build Coastguard Worker   buffer->HasEnsuredCapacity = true;
85*03ce13f7SAndroid Build Coastguard Worker }
86*03ce13f7SAndroid Build Coastguard Worker 
~EnsureCapacity()87*03ce13f7SAndroid Build Coastguard Worker AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
88*03ce13f7SAndroid Build Coastguard Worker   // Unmark the buffer, so we cannot emit after this.
89*03ce13f7SAndroid Build Coastguard Worker   Buffer->HasEnsuredCapacity = false;
90*03ce13f7SAndroid Build Coastguard Worker   // Make sure the generated instruction doesn't take up more space than the
91*03ce13f7SAndroid Build Coastguard Worker   // minimum gap.
92*03ce13f7SAndroid Build Coastguard Worker   intptr_t delta = Gap - computeGap();
93*03ce13f7SAndroid Build Coastguard Worker   (void)delta;
94*03ce13f7SAndroid Build Coastguard Worker   assert(delta <= kMinimumGap);
95*03ce13f7SAndroid Build Coastguard Worker }
96*03ce13f7SAndroid Build Coastguard Worker 
AssemblerBuffer(Assembler & Asm)97*03ce13f7SAndroid Build Coastguard Worker AssemblerBuffer::AssemblerBuffer(Assembler &Asm) : Assemblr(Asm) {
98*03ce13f7SAndroid Build Coastguard Worker   constexpr intptr_t OneKB = 1024;
99*03ce13f7SAndroid Build Coastguard Worker   static constexpr intptr_t kInitialBufferCapacity = 4 * OneKB;
100*03ce13f7SAndroid Build Coastguard Worker   Contents = NewContents(Assemblr, kInitialBufferCapacity);
101*03ce13f7SAndroid Build Coastguard Worker   Cursor = Contents;
102*03ce13f7SAndroid Build Coastguard Worker   Limit = computeLimit(Contents, kInitialBufferCapacity);
103*03ce13f7SAndroid Build Coastguard Worker   HasEnsuredCapacity = false;
104*03ce13f7SAndroid Build Coastguard Worker   TextFixupNeeded = false;
105*03ce13f7SAndroid Build Coastguard Worker 
106*03ce13f7SAndroid Build Coastguard Worker   // Verify internal state.
107*03ce13f7SAndroid Build Coastguard Worker   assert(capacity() == kInitialBufferCapacity);
108*03ce13f7SAndroid Build Coastguard Worker   assert(size() == 0);
109*03ce13f7SAndroid Build Coastguard Worker }
110*03ce13f7SAndroid Build Coastguard Worker 
111*03ce13f7SAndroid Build Coastguard Worker AssemblerBuffer::~AssemblerBuffer() = default;
112*03ce13f7SAndroid Build Coastguard Worker 
extendCapacity()113*03ce13f7SAndroid Build Coastguard Worker void AssemblerBuffer::extendCapacity() {
114*03ce13f7SAndroid Build Coastguard Worker   intptr_t old_size = size();
115*03ce13f7SAndroid Build Coastguard Worker   intptr_t old_capacity = capacity();
116*03ce13f7SAndroid Build Coastguard Worker   constexpr intptr_t OneMB = 1 << 20;
117*03ce13f7SAndroid Build Coastguard Worker   intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB);
118*03ce13f7SAndroid Build Coastguard Worker   if (new_capacity < old_capacity) {
119*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error(
120*03ce13f7SAndroid Build Coastguard Worker         "Unexpected overflow in AssemblerBuffer::ExtendCapacity");
121*03ce13f7SAndroid Build Coastguard Worker   }
122*03ce13f7SAndroid Build Coastguard Worker 
123*03ce13f7SAndroid Build Coastguard Worker   // Allocate the new data area and copy contents of the old one to it.
124*03ce13f7SAndroid Build Coastguard Worker   uintptr_t new_contents = NewContents(Assemblr, new_capacity);
125*03ce13f7SAndroid Build Coastguard Worker   memmove(reinterpret_cast<void *>(new_contents),
126*03ce13f7SAndroid Build Coastguard Worker           reinterpret_cast<void *>(Contents), old_size);
127*03ce13f7SAndroid Build Coastguard Worker 
128*03ce13f7SAndroid Build Coastguard Worker   // Compute the relocation delta and switch to the new contents area.
129*03ce13f7SAndroid Build Coastguard Worker   intptr_t delta = new_contents - Contents;
130*03ce13f7SAndroid Build Coastguard Worker   Contents = new_contents;
131*03ce13f7SAndroid Build Coastguard Worker 
132*03ce13f7SAndroid Build Coastguard Worker   // Update the cursor and recompute the limit.
133*03ce13f7SAndroid Build Coastguard Worker   Cursor += delta;
134*03ce13f7SAndroid Build Coastguard Worker   Limit = computeLimit(new_contents, new_capacity);
135*03ce13f7SAndroid Build Coastguard Worker 
136*03ce13f7SAndroid Build Coastguard Worker   // Verify internal state.
137*03ce13f7SAndroid Build Coastguard Worker   assert(capacity() == new_capacity);
138*03ce13f7SAndroid Build Coastguard Worker   assert(size() == old_size);
139*03ce13f7SAndroid Build Coastguard Worker }
140*03ce13f7SAndroid Build Coastguard Worker 
getBufferView() const141*03ce13f7SAndroid Build Coastguard Worker llvm::StringRef Assembler::getBufferView() const {
142*03ce13f7SAndroid Build Coastguard Worker   return llvm::StringRef(reinterpret_cast<const char *>(Buffer.contents()),
143*03ce13f7SAndroid Build Coastguard Worker                          Buffer.size());
144*03ce13f7SAndroid Build Coastguard Worker }
145*03ce13f7SAndroid Build Coastguard Worker 
bindRelocOffset(RelocOffset * Offset)146*03ce13f7SAndroid Build Coastguard Worker void Assembler::bindRelocOffset(RelocOffset *Offset) {
147*03ce13f7SAndroid Build Coastguard Worker   if (!getPreliminary()) {
148*03ce13f7SAndroid Build Coastguard Worker     Offset->setOffset(Buffer.getPosition());
149*03ce13f7SAndroid Build Coastguard Worker   }
150*03ce13f7SAndroid Build Coastguard Worker }
151*03ce13f7SAndroid Build Coastguard Worker 
emitIASBytes(GlobalContext * Ctx) const152*03ce13f7SAndroid Build Coastguard Worker void Assembler::emitIASBytes(GlobalContext *Ctx) const {
153*03ce13f7SAndroid Build Coastguard Worker   Ostream &Str = Ctx->getStrEmit();
154*03ce13f7SAndroid Build Coastguard Worker   intptr_t EndPosition = Buffer.size();
155*03ce13f7SAndroid Build Coastguard Worker   intptr_t CurPosition = 0;
156*03ce13f7SAndroid Build Coastguard Worker   for (const AssemblerFixup *NextFixup : fixups()) {
157*03ce13f7SAndroid Build Coastguard Worker     intptr_t NextFixupLoc = NextFixup->position();
158*03ce13f7SAndroid Build Coastguard Worker     for (intptr_t i = CurPosition; i < NextFixupLoc; ++i) {
159*03ce13f7SAndroid Build Coastguard Worker       Str << "\t.byte 0x";
160*03ce13f7SAndroid Build Coastguard Worker       Str.write_hex(Buffer.load<uint8_t>(i));
161*03ce13f7SAndroid Build Coastguard Worker       Str << "\n";
162*03ce13f7SAndroid Build Coastguard Worker     }
163*03ce13f7SAndroid Build Coastguard Worker     CurPosition = NextFixupLoc + NextFixup->emit(Ctx, *this);
164*03ce13f7SAndroid Build Coastguard Worker     assert(CurPosition <= EndPosition);
165*03ce13f7SAndroid Build Coastguard Worker   }
166*03ce13f7SAndroid Build Coastguard Worker   // Handle any bytes that are not prefixed by a fixup.
167*03ce13f7SAndroid Build Coastguard Worker   for (intptr_t i = CurPosition; i < EndPosition; ++i) {
168*03ce13f7SAndroid Build Coastguard Worker     Str << "\t.byte 0x";
169*03ce13f7SAndroid Build Coastguard Worker     Str.write_hex(Buffer.load<uint8_t>(i));
170*03ce13f7SAndroid Build Coastguard Worker     Str << "\n";
171*03ce13f7SAndroid Build Coastguard Worker   }
172*03ce13f7SAndroid Build Coastguard Worker }
173*03ce13f7SAndroid Build Coastguard Worker 
174*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
175