Skip to content

Reland [AMDGPU] Add AMDGPU specific variadic operation MCExprs #84562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions llvm/docs/AMDGPUUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1534,6 +1534,25 @@ The AMDGPU backend supports the following calling conventions:

=============================== ==========================================================

AMDGPU MCExpr
-------------

As part of the AMDGPU MC layer, AMDGPU provides the following target specific
``MCExpr``\s.

.. table:: AMDGPU MCExpr types:
:name: amdgpu-mcexpr-table

=================== ================= ========================================================
MCExpr Operands Return value
=================== ================= ========================================================
``max(arg, ...)`` 1 or more Variadic signed operation that returns the maximum
value of all its arguments.

``or(arg, ...)`` 1 or more Variadic signed operation that returns the bitwise-or
result of all its arguments.

=================== ================= ========================================================

.. _amdgpu-elf-code-object:

Expand Down
55 changes: 55 additions & 0 deletions llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "AMDKernelCodeT.h"
#include "MCTargetDesc/AMDGPUMCExpr.h"
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "MCTargetDesc/AMDGPUTargetStreamer.h"
#include "SIDefines.h"
Expand Down Expand Up @@ -1816,6 +1817,7 @@ class AMDGPUAsmParser : public MCTargetAsmParser {

public:
void onBeginOfFile() override;
bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override;

ParseStatus parseCustomOperand(OperandVector &Operands, unsigned MCK);

Expand Down Expand Up @@ -8277,6 +8279,59 @@ void AMDGPUAsmParser::onBeginOfFile() {
getTargetStreamer().EmitDirectiveAMDGCNTarget();
}

/// Parse AMDGPU specific expressions.
///
/// expr ::= or(expr, ...) |
/// max(expr, ...)
///
bool AMDGPUAsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
using AGVK = AMDGPUVariadicMCExpr::VariadicKind;

if (isToken(AsmToken::Identifier)) {
StringRef TokenId = getTokenStr();
AGVK VK = StringSwitch<AGVK>(TokenId)
.Case("max", AGVK::AGVK_Max)
.Case("or", AGVK::AGVK_Or)
.Default(AGVK::AGVK_None);

if (VK != AGVK::AGVK_None && peekToken().is(AsmToken::LParen)) {
SmallVector<const MCExpr *, 4> Exprs;
uint64_t CommaCount = 0;
lex(); // Eat 'max'/'or'
lex(); // Eat '('
while (true) {
if (trySkipToken(AsmToken::RParen)) {
if (Exprs.empty()) {
Error(getToken().getLoc(),
"empty " + Twine(TokenId) + " expression");
return true;
}
if (CommaCount + 1 != Exprs.size()) {
Error(getToken().getLoc(),
"mismatch of commas in " + Twine(TokenId) + " expression");
return true;
}
Res = AMDGPUVariadicMCExpr::create(VK, Exprs, getContext());
return false;
}
const MCExpr *Expr;
if (getParser().parseExpression(Expr, EndLoc))
return true;
Exprs.push_back(Expr);
bool LastTokenWasComma = trySkipToken(AsmToken::Comma);
if (LastTokenWasComma)
CommaCount++;
if (!LastTokenWasComma && !isToken(AsmToken::RParen)) {
Error(getToken().getLoc(),
"unexpected token in " + Twine(TokenId) + " expression");
return true;
}
}
}
}
return getParser().parsePrimaryExpr(Res, EndLoc, nullptr);
}

ParseStatus AMDGPUAsmParser::parseOModSI(OperandVector &Operands) {
StringRef Name = getTokenStr();
if (Name == "mul") {
Expand Down
115 changes: 115 additions & 0 deletions llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//===- AMDGPUMCExpr.cpp - AMDGPU specific MC expression classes -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "AMDGPUMCExpr.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>

using namespace llvm;

AMDGPUVariadicMCExpr::AMDGPUVariadicMCExpr(VariadicKind Kind,
ArrayRef<const MCExpr *> Args,
MCContext &Ctx)
: Kind(Kind), Ctx(Ctx) {
assert(Args.size() >= 1 && "Needs a minimum of one expression.");
assert(Kind != AGVK_None &&
"Cannot construct AMDGPUVariadicMCExpr of kind none.");

// Allocating the variadic arguments through the same allocation mechanism
// that the object itself is allocated with so they end up in the same memory.
//
// Will result in an asan failure if allocated on the heap through standard
// allocation (e.g., through SmallVector's grow).
RawArgs = static_cast<const MCExpr **>(
Ctx.allocate(sizeof(const MCExpr *) * Args.size()));
std::uninitialized_copy(Args.begin(), Args.end(), RawArgs);
this->Args = ArrayRef<const MCExpr *>(RawArgs, Args.size());
}

AMDGPUVariadicMCExpr::~AMDGPUVariadicMCExpr() { Ctx.deallocate(RawArgs); }

const AMDGPUVariadicMCExpr *
AMDGPUVariadicMCExpr::create(VariadicKind Kind, ArrayRef<const MCExpr *> Args,
MCContext &Ctx) {
return new (Ctx) AMDGPUVariadicMCExpr(Kind, Args, Ctx);
}

const MCExpr *AMDGPUVariadicMCExpr::getSubExpr(size_t Index) const {
assert(Index < Args.size() &&
"Indexing out of bounds AMDGPUVariadicMCExpr sub-expr");
return Args[Index];
}

void AMDGPUVariadicMCExpr::printImpl(raw_ostream &OS,
const MCAsmInfo *MAI) const {
switch (Kind) {
default:
llvm_unreachable("Unknown AMDGPUVariadicMCExpr kind.");
case AGVK_Or:
OS << "or(";
break;
case AGVK_Max:
OS << "max(";
break;
}
for (auto It = Args.begin(); It != Args.end(); ++It) {
(*It)->print(OS, MAI, /*InParens=*/false);
if ((It + 1) != Args.end())
OS << ", ";
}
OS << ')';
}

static int64_t op(AMDGPUVariadicMCExpr::VariadicKind Kind, int64_t Arg1,
int64_t Arg2) {
switch (Kind) {
default:
llvm_unreachable("Unknown AMDGPUVariadicMCExpr kind.");
case AMDGPUVariadicMCExpr::AGVK_Max:
return std::max(Arg1, Arg2);
case AMDGPUVariadicMCExpr::AGVK_Or:
return Arg1 | Arg2;
}
}

bool AMDGPUVariadicMCExpr::evaluateAsRelocatableImpl(
MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const {
std::optional<int64_t> Total;

for (const MCExpr *Arg : Args) {
MCValue ArgRes;
if (!Arg->evaluateAsRelocatable(ArgRes, Layout, Fixup) ||
!ArgRes.isAbsolute())
return false;

if (!Total.has_value())
Total = ArgRes.getConstant();
Total = op(Kind, *Total, ArgRes.getConstant());
}

Res = MCValue::get(*Total);
return true;
}

void AMDGPUVariadicMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
for (const MCExpr *Arg : Args)
Streamer.visitUsedExpr(*Arg);
}

MCFragment *AMDGPUVariadicMCExpr::findAssociatedFragment() const {
for (const MCExpr *Arg : Args) {
if (Arg->findAssociatedFragment())
return Arg->findAssociatedFragment();
}
return nullptr;
}
72 changes: 72 additions & 0 deletions llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//===- AMDGPUMCExpr.h - AMDGPU specific MC expression classes ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_AMDGPU_MCTARGETDESC_AMDGPUMCEXPR_H
#define LLVM_LIB_TARGET_AMDGPU_MCTARGETDESC_AMDGPUMCEXPR_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/MC/MCExpr.h"

namespace llvm {

/// AMDGPU target specific variadic MCExpr operations.
///
/// Takes in a minimum of 1 argument to be used with an operation. The supported
/// operations are:
/// - (bitwise) or
/// - max
///
/// \note If the 'or'/'max' operations are provided only a single argument, the
/// operation will act as a no-op and simply resolve as the provided argument.
///
class AMDGPUVariadicMCExpr : public MCTargetExpr {
public:
enum VariadicKind { AGVK_None, AGVK_Or, AGVK_Max };

private:
VariadicKind Kind;
MCContext &Ctx;
const MCExpr **RawArgs;
ArrayRef<const MCExpr *> Args;

AMDGPUVariadicMCExpr(VariadicKind Kind, ArrayRef<const MCExpr *> Args,
MCContext &Ctx);
~AMDGPUVariadicMCExpr();

public:
static const AMDGPUVariadicMCExpr *
create(VariadicKind Kind, ArrayRef<const MCExpr *> Args, MCContext &Ctx);

static const AMDGPUVariadicMCExpr *createOr(ArrayRef<const MCExpr *> Args,
MCContext &Ctx) {
return create(VariadicKind::AGVK_Or, Args, Ctx);
}

static const AMDGPUVariadicMCExpr *createMax(ArrayRef<const MCExpr *> Args,
MCContext &Ctx) {
return create(VariadicKind::AGVK_Max, Args, Ctx);
}

VariadicKind getKind() const { return Kind; }
const MCExpr *getSubExpr(size_t Index) const;

void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
const MCFixup *Fixup) const override;
void visitUsedExpr(MCStreamer &Streamer) const override;
MCFragment *findAssociatedFragment() const override;
void fixELFSymbolsInTLSFixups(MCAssembler &) const override{};

static bool classof(const MCExpr *E) {
return E->getKind() == MCExpr::Target;
}
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_AMDGPU_MCTARGETDESC_AMDGPUMCEXPR_H
1 change: 1 addition & 0 deletions llvm/lib/Target/AMDGPU/MCTargetDesc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_llvm_component_library(LLVMAMDGPUDesc
AMDGPUInstPrinter.cpp
AMDGPUMCAsmInfo.cpp
AMDGPUMCCodeEmitter.cpp
AMDGPUMCExpr.cpp
AMDGPUMCTargetDesc.cpp
AMDGPUTargetStreamer.cpp
R600InstPrinter.cpp
Expand Down
Loading