Skip to content

Commit

Permalink
Merge pull request #7282 from jdmpapin/inl-const-replay
Browse files Browse the repository at this point in the history
Facilitate recording of constants observed in call target selection
  • Loading branch information
vijaysun-omr authored Mar 14, 2024
2 parents 6625248 + d87f2bb commit 1bf2ef4
Show file tree
Hide file tree
Showing 9 changed files with 380 additions and 4 deletions.
1 change: 1 addition & 0 deletions compiler/compile/OMRCompilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ OMR::Compilation::Compilation(
_gpuPtxCount(0),
_bitVectorPool(self()),
_typeLayoutMap((LayoutComparator()), LayoutAllocator(self()->region())),
_currentILGenCallTarget(NULL),
_tlsManager(*self())
{
if (target != NULL)
Expand Down
21 changes: 21 additions & 0 deletions compiler/compile/OMRCompilation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ namespace OMR { typedef OMR::Compilation CompilationConnector; }

class TR_AOTGuardSite;
class TR_BitVector;
struct TR_CallTarget;
class TR_CHTable;
class TR_FrontEnd;
class TR_HWPRecord;
Expand Down Expand Up @@ -1125,6 +1126,24 @@ class OMR_EXTENSIBLE Compilation
*/
TR::Environment& target() { return _target; }

/**
* \brief
* The inline call target, if any, for which IL is currently being generated.
*
* \return
* the call target
*/
TR_CallTarget *currentILGenCallTarget() { return _currentILGenCallTarget; }

/**
* \brief
* Set the inline call target for which IL is currently being generated.
*
* This should be set in the inliner just prior to generating IL to inline,
* and it should be reset to null afterward.
*/
void setCurrentILGenCallTarget(TR_CallTarget *x) { _currentILGenCallTarget = x; }

private:
void resetVisitCounts(vcount_t, TR::ResolvedMethodSymbol *);
int16_t restoreInlineDepthUntil(int32_t stopIndex, TR_ByteCodeInfo &currentInfo);
Expand Down Expand Up @@ -1332,6 +1351,8 @@ class OMR_EXTENSIBLE Compilation
typedef std::map<TR_OpaqueClassBlock *, const TR::TypeLayout *, LayoutComparator, LayoutAllocator> TypeLayoutMap;
TypeLayoutMap _typeLayoutMap;

TR_CallTarget *_currentILGenCallTarget;

/*
* This must be last
* NOTE: TLS for Compilation needs to be set before any object that may use it is initialized.
Expand Down
114 changes: 114 additions & 0 deletions compiler/il/AnyConst.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*******************************************************************************
* Copyright IBM Corp. and others 2024
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution
* and is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception [1] and GNU General Public
* License, version 2 with the OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] https://openjdk.org/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
*******************************************************************************/

#ifndef ANYCONST_INCL
#define ANYCONST_INCL

#include "env/KnownObjectTable.hpp"
#include "infra/Assert.hpp"
#include <stdint.h>

namespace TR {

/**
* \brief A value of arbitrary type that could be the result of a node.
*
* The value is constant just in the sense that it is known at compile time.
*/
class AnyConst
{
enum Kind
{
KindInt8,
KindInt16,
KindInt32,
KindInt64,
KindFloat,
KindDouble,
KindAddress,
KindKnownObject,
};

Kind _kind;
union
{
float _float;
double _double;
uint64_t _integral; // for everything else
};

AnyConst(Kind kind, uint64_t x) : _kind(kind), _integral(x) {}
AnyConst(float x) : _kind(KindFloat), _float(x) {}
AnyConst(double x) : _kind(KindDouble), _double(x) {}

public:

static AnyConst makeInt8(uint8_t x) { return AnyConst(KindInt8, x); }
static AnyConst makeInt16(uint16_t x) { return AnyConst(KindInt16, x); }
static AnyConst makeInt32(uint32_t x) { return AnyConst(KindInt32, x); }
static AnyConst makeInt64(uint64_t x) { return AnyConst(KindInt64, x); }
static AnyConst makeFloat(float x) { return AnyConst(x); }
static AnyConst makeDouble(double x) { return AnyConst(x); }

// Address: mostly for null, but can be used for pointers to data structures
// that don't move and for object references while VM access is held.
static AnyConst makeAddress(uintptr_t x) { return AnyConst(KindAddress, x); }

static AnyConst makeKnownObject(TR::KnownObjectTable::Index i)
{
TR_ASSERT_FATAL(i != TR::KnownObjectTable::UNKNOWN, "should be known");
return AnyConst(KindKnownObject, i);
}

bool isInt8() const { return _kind == KindInt8; }
bool isInt16() const { return _kind == KindInt16; }
bool isInt32() const { return _kind == KindInt32; }
bool isInt64() const { return _kind == KindInt64; }
bool isFloat() const { return _kind == KindFloat; }
bool isDouble() const { return _kind == KindDouble; }
bool isAddress() const { return _kind == KindAddress; }
bool isKnownObject() const { return _kind == KindKnownObject; }

uint8_t getInt8() const { kindAssert(KindInt8); return (uint8_t)_integral; }
uint16_t getInt16() const { kindAssert(KindInt16); return (uint16_t)_integral; }
uint32_t getInt32() const { kindAssert(KindInt32); return (uint32_t)_integral; }
uint64_t getInt64() const { kindAssert(KindInt64); return (uint64_t)_integral; }
float getFloat() const { kindAssert(KindFloat); return _float; }
double getDouble() const { kindAssert(KindDouble); return _double; }
uintptr_t getAddress() const { kindAssert(KindAddress); return (uintptr_t)_integral; }

TR::KnownObjectTable::Index getKnownObjectIndex() const
{
kindAssert(KindKnownObject);
return (TR::KnownObjectTable::Index)_integral;
}

private:

void kindAssert(Kind expected) const
{
TR_ASSERT_FATAL(_kind == expected, "type mismatch");
}
};

} // namespace TR

#endif // ANYCONST_INCL
57 changes: 57 additions & 0 deletions compiler/infra/map.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright IBM Corp. and others 2017
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at http://eclipse.org/legal/epl-2.0
* or the Apache License, Version 2.0 which accompanies this distribution
* and is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception [1] and GNU General Public
* License, version 2 with the OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

#ifndef TR_MAP_HPP
#define TR_MAP_HPP

#pragma once

#include <map>
#include "env/Region.hpp"
#include "env/TRMemory.hpp"
#include "env/TypedAllocator.hpp"

namespace TR {

template <
typename K,
typename V,
typename Cmp = std::less<K>,
typename Alloc = TR::Region&
>
class map : public std::map<K, V, Cmp, TR::typed_allocator<std::pair<const K, V>, Alloc> >
{
private:
typedef std::map<K, V, Cmp, TR::typed_allocator<std::pair<const K, V>, Alloc> > Base;

public:
typedef typename Base::key_compare key_compare;
typedef typename Base::allocator_type allocator_type;

map(const key_compare &cmp, const allocator_type &alloc) : Base(cmp, alloc) {}

// This constructor is available when the comparison is default-constructible.
map(const allocator_type &alloc) : Base(key_compare(), alloc) {}
};

} // namespace TR

#endif // TR_MAP_HPP
56 changes: 56 additions & 0 deletions compiler/infra/set.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright IBM Corp. and others 2017
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at http://eclipse.org/legal/epl-2.0
* or the Apache License, Version 2.0 which accompanies this distribution
* and is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception [1] and GNU General Public
* License, version 2 with the OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

#ifndef TR_SET_HPP
#define TR_SET_HPP

#pragma once

#include <set>
#include "env/Region.hpp"
#include "env/TRMemory.hpp"
#include "env/TypedAllocator.hpp"

namespace TR {

template <
typename T,
typename Cmp = std::less<T>,
typename Alloc = TR::Region&
>
class set : public std::set<T, Cmp, TR::typed_allocator<T, Alloc> >
{
private:
typedef std::set<T, Cmp, TR::typed_allocator<T, Alloc> > Base;

public:
typedef typename Base::value_compare value_compare;
typedef typename Base::allocator_type allocator_type;

set(const value_compare &cmp, const allocator_type &alloc) : Base(cmp, alloc) {}

// This constructor is available when the comparison is default-constructible.
set(const allocator_type &alloc) : Base(value_compare(), alloc) {}
};

} // namespace TR

#endif // TR_SET_HPP
44 changes: 43 additions & 1 deletion compiler/optimizer/CallInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@
#include "compile/Compilation.hpp"
#include "env/TRMemory.hpp"
#include "env/jittypes.h"
#include "il/AnyConst.hpp"
#include "il/MethodSymbol.hpp"
#include "il/Node.hpp"
#include "infra/Assert.hpp"
#include "infra/deque.hpp"
#include "infra/Link.hpp"
#include "infra/List.hpp"
#include "infra/map.hpp"
#include "infra/TRlist.hpp"
#include "optimizer/DeferredOSRAssumption.hpp"
#include "optimizer/InlinerFailureReason.hpp"

namespace TR { class CompilationFilters;}
Expand All @@ -59,6 +63,8 @@ namespace TR { class TreeTop; }
class TR_CallSite;
struct TR_VirtualGuardSelection;

namespace TR { struct RequiredConst; }

class TR_CallStack : public TR_Link<TR_CallStack>
{
public:
Expand Down Expand Up @@ -127,13 +133,43 @@ class TR_CallStack : public TR_Link<TR_CallStack>

};

namespace TR {

/**
* \brief A constant value that was observed during call target selection.
*
* When IL is generated for a call target, it's necessary in general to repeat
* any constant folding that occurred while selecting targets recursively
* within it so that the IL is guaranteed to match what the inliner saw.
*
* This repeated folding is important whenever a value might be allowed to be
* folded despite the possibility of a later change. It also allows constants
* to be speculative by specifying the assumptions that are necessary in order
* for the folding to be correct, and by informing the IL generator of the
* locations where such assumptions have been made (though the locations are
* tracked externally to this class).
*/
struct RequiredConst
{
TR::AnyConst _value; ///< The value.

/// The assumptions required to guarantee the value is constant, if any.
TR::list<TR::DeferredOSRAssumption*, TR::Region&> _assumptions;

RequiredConst(const TR::AnyConst &value, TR::Region &region)
: _value(value), _assumptions(region) {}
};

} // namespace TR

struct TR_CallTarget : public TR_Link<TR_CallTarget>
{
TR_ALLOC(TR_Memory::Inliner);

friend class TR_InlinerTracer;

TR_CallTarget(TR_CallSite *callsite,
TR_CallTarget(TR::Region &memRegion,
TR_CallSite *callsite,
TR::ResolvedMethodSymbol *calleeSymbol,
TR_ResolvedMethod *calleeMethod,
TR_VirtualGuardSelection *guard,
Expand Down Expand Up @@ -190,6 +226,12 @@ struct TR_CallTarget : public TR_Link<TR_CallTarget>
TR_PrexArgInfo *_prexArgInfo; // used by computePrexInfo to calculate prex on generatedIL and transform IL
TR_PrexArgInfo *_ecsPrexArgInfo; // used by ECS and findInlineTargets to assist in choosing correct inline targets

/**
* \brief Constant values that were observed during call target selection
* within this particular call target, keyed on bytecode index.
*/
TR::map<int32_t, TR::RequiredConst> _requiredConsts;

void addDeadCallee(TR_CallSite *cs)
{
_deletedCallees.add(cs);
Expand Down
Loading

0 comments on commit 1bf2ef4

Please sign in to comment.