Skip to content

Commit f7bebc1

Browse files
authored
Reland [AMDGPU] Add AMDGPU specific variadic operation MCExprs (#84562)
Adds AMDGPU specific variadic MCExpr operations 'max' and 'or'. Relands #82022 with fixes
1 parent 2d6988a commit f7bebc1

File tree

7 files changed

+445
-0
lines changed

7 files changed

+445
-0
lines changed

llvm/docs/AMDGPUUsage.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,25 @@ The AMDGPU backend supports the following calling conventions:
15521552

15531553
=============================== ==========================================================
15541554

1555+
AMDGPU MCExpr
1556+
-------------
1557+
1558+
As part of the AMDGPU MC layer, AMDGPU provides the following target specific
1559+
``MCExpr``\s.
1560+
1561+
.. table:: AMDGPU MCExpr types:
1562+
:name: amdgpu-mcexpr-table
1563+
1564+
=================== ================= ========================================================
1565+
MCExpr Operands Return value
1566+
=================== ================= ========================================================
1567+
``max(arg, ...)`` 1 or more Variadic signed operation that returns the maximum
1568+
value of all its arguments.
1569+
1570+
``or(arg, ...)`` 1 or more Variadic signed operation that returns the bitwise-or
1571+
result of all its arguments.
1572+
1573+
=================== ================= ========================================================
15551574

15561575
.. _amdgpu-elf-code-object:
15571576

llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "AMDKernelCodeT.h"
10+
#include "MCTargetDesc/AMDGPUMCExpr.h"
1011
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
1112
#include "MCTargetDesc/AMDGPUTargetStreamer.h"
1213
#include "SIDefines.h"
@@ -1816,6 +1817,7 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
18161817

18171818
public:
18181819
void onBeginOfFile() override;
1820+
bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override;
18191821

18201822
ParseStatus parseCustomOperand(OperandVector &Operands, unsigned MCK);
18211823

@@ -8330,6 +8332,59 @@ void AMDGPUAsmParser::onBeginOfFile() {
83308332
getTargetStreamer().EmitDirectiveAMDGCNTarget();
83318333
}
83328334

8335+
/// Parse AMDGPU specific expressions.
8336+
///
8337+
/// expr ::= or(expr, ...) |
8338+
/// max(expr, ...)
8339+
///
8340+
bool AMDGPUAsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
8341+
using AGVK = AMDGPUVariadicMCExpr::VariadicKind;
8342+
8343+
if (isToken(AsmToken::Identifier)) {
8344+
StringRef TokenId = getTokenStr();
8345+
AGVK VK = StringSwitch<AGVK>(TokenId)
8346+
.Case("max", AGVK::AGVK_Max)
8347+
.Case("or", AGVK::AGVK_Or)
8348+
.Default(AGVK::AGVK_None);
8349+
8350+
if (VK != AGVK::AGVK_None && peekToken().is(AsmToken::LParen)) {
8351+
SmallVector<const MCExpr *, 4> Exprs;
8352+
uint64_t CommaCount = 0;
8353+
lex(); // Eat 'max'/'or'
8354+
lex(); // Eat '('
8355+
while (true) {
8356+
if (trySkipToken(AsmToken::RParen)) {
8357+
if (Exprs.empty()) {
8358+
Error(getToken().getLoc(),
8359+
"empty " + Twine(TokenId) + " expression");
8360+
return true;
8361+
}
8362+
if (CommaCount + 1 != Exprs.size()) {
8363+
Error(getToken().getLoc(),
8364+
"mismatch of commas in " + Twine(TokenId) + " expression");
8365+
return true;
8366+
}
8367+
Res = AMDGPUVariadicMCExpr::create(VK, Exprs, getContext());
8368+
return false;
8369+
}
8370+
const MCExpr *Expr;
8371+
if (getParser().parseExpression(Expr, EndLoc))
8372+
return true;
8373+
Exprs.push_back(Expr);
8374+
bool LastTokenWasComma = trySkipToken(AsmToken::Comma);
8375+
if (LastTokenWasComma)
8376+
CommaCount++;
8377+
if (!LastTokenWasComma && !isToken(AsmToken::RParen)) {
8378+
Error(getToken().getLoc(),
8379+
"unexpected token in " + Twine(TokenId) + " expression");
8380+
return true;
8381+
}
8382+
}
8383+
}
8384+
}
8385+
return getParser().parsePrimaryExpr(Res, EndLoc, nullptr);
8386+
}
8387+
83338388
ParseStatus AMDGPUAsmParser::parseOModSI(OperandVector &Operands) {
83348389
StringRef Name = getTokenStr();
83358390
if (Name == "mul") {
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//===- AMDGPUMCExpr.cpp - AMDGPU specific MC expression classes -----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "AMDGPUMCExpr.h"
10+
#include "llvm/MC/MCContext.h"
11+
#include "llvm/MC/MCStreamer.h"
12+
#include "llvm/MC/MCSymbol.h"
13+
#include "llvm/MC/MCValue.h"
14+
#include "llvm/Support/Allocator.h"
15+
#include "llvm/Support/raw_ostream.h"
16+
#include <optional>
17+
18+
using namespace llvm;
19+
20+
AMDGPUVariadicMCExpr::AMDGPUVariadicMCExpr(VariadicKind Kind,
21+
ArrayRef<const MCExpr *> Args,
22+
MCContext &Ctx)
23+
: Kind(Kind), Ctx(Ctx) {
24+
assert(Args.size() >= 1 && "Needs a minimum of one expression.");
25+
assert(Kind != AGVK_None &&
26+
"Cannot construct AMDGPUVariadicMCExpr of kind none.");
27+
28+
// Allocating the variadic arguments through the same allocation mechanism
29+
// that the object itself is allocated with so they end up in the same memory.
30+
//
31+
// Will result in an asan failure if allocated on the heap through standard
32+
// allocation (e.g., through SmallVector's grow).
33+
RawArgs = static_cast<const MCExpr **>(
34+
Ctx.allocate(sizeof(const MCExpr *) * Args.size()));
35+
std::uninitialized_copy(Args.begin(), Args.end(), RawArgs);
36+
this->Args = ArrayRef<const MCExpr *>(RawArgs, Args.size());
37+
}
38+
39+
AMDGPUVariadicMCExpr::~AMDGPUVariadicMCExpr() { Ctx.deallocate(RawArgs); }
40+
41+
const AMDGPUVariadicMCExpr *
42+
AMDGPUVariadicMCExpr::create(VariadicKind Kind, ArrayRef<const MCExpr *> Args,
43+
MCContext &Ctx) {
44+
return new (Ctx) AMDGPUVariadicMCExpr(Kind, Args, Ctx);
45+
}
46+
47+
const MCExpr *AMDGPUVariadicMCExpr::getSubExpr(size_t Index) const {
48+
assert(Index < Args.size() &&
49+
"Indexing out of bounds AMDGPUVariadicMCExpr sub-expr");
50+
return Args[Index];
51+
}
52+
53+
void AMDGPUVariadicMCExpr::printImpl(raw_ostream &OS,
54+
const MCAsmInfo *MAI) const {
55+
switch (Kind) {
56+
default:
57+
llvm_unreachable("Unknown AMDGPUVariadicMCExpr kind.");
58+
case AGVK_Or:
59+
OS << "or(";
60+
break;
61+
case AGVK_Max:
62+
OS << "max(";
63+
break;
64+
}
65+
for (auto It = Args.begin(); It != Args.end(); ++It) {
66+
(*It)->print(OS, MAI, /*InParens=*/false);
67+
if ((It + 1) != Args.end())
68+
OS << ", ";
69+
}
70+
OS << ')';
71+
}
72+
73+
static int64_t op(AMDGPUVariadicMCExpr::VariadicKind Kind, int64_t Arg1,
74+
int64_t Arg2) {
75+
switch (Kind) {
76+
default:
77+
llvm_unreachable("Unknown AMDGPUVariadicMCExpr kind.");
78+
case AMDGPUVariadicMCExpr::AGVK_Max:
79+
return std::max(Arg1, Arg2);
80+
case AMDGPUVariadicMCExpr::AGVK_Or:
81+
return Arg1 | Arg2;
82+
}
83+
}
84+
85+
bool AMDGPUVariadicMCExpr::evaluateAsRelocatableImpl(
86+
MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const {
87+
std::optional<int64_t> Total;
88+
89+
for (const MCExpr *Arg : Args) {
90+
MCValue ArgRes;
91+
if (!Arg->evaluateAsRelocatable(ArgRes, Layout, Fixup) ||
92+
!ArgRes.isAbsolute())
93+
return false;
94+
95+
if (!Total.has_value())
96+
Total = ArgRes.getConstant();
97+
Total = op(Kind, *Total, ArgRes.getConstant());
98+
}
99+
100+
Res = MCValue::get(*Total);
101+
return true;
102+
}
103+
104+
void AMDGPUVariadicMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
105+
for (const MCExpr *Arg : Args)
106+
Streamer.visitUsedExpr(*Arg);
107+
}
108+
109+
MCFragment *AMDGPUVariadicMCExpr::findAssociatedFragment() const {
110+
for (const MCExpr *Arg : Args) {
111+
if (Arg->findAssociatedFragment())
112+
return Arg->findAssociatedFragment();
113+
}
114+
return nullptr;
115+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//===- AMDGPUMCExpr.h - AMDGPU specific MC expression classes ---*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIB_TARGET_AMDGPU_MCTARGETDESC_AMDGPUMCEXPR_H
10+
#define LLVM_LIB_TARGET_AMDGPU_MCTARGETDESC_AMDGPUMCEXPR_H
11+
12+
#include "llvm/ADT/ArrayRef.h"
13+
#include "llvm/MC/MCExpr.h"
14+
15+
namespace llvm {
16+
17+
/// AMDGPU target specific variadic MCExpr operations.
18+
///
19+
/// Takes in a minimum of 1 argument to be used with an operation. The supported
20+
/// operations are:
21+
/// - (bitwise) or
22+
/// - max
23+
///
24+
/// \note If the 'or'/'max' operations are provided only a single argument, the
25+
/// operation will act as a no-op and simply resolve as the provided argument.
26+
///
27+
class AMDGPUVariadicMCExpr : public MCTargetExpr {
28+
public:
29+
enum VariadicKind { AGVK_None, AGVK_Or, AGVK_Max };
30+
31+
private:
32+
VariadicKind Kind;
33+
MCContext &Ctx;
34+
const MCExpr **RawArgs;
35+
ArrayRef<const MCExpr *> Args;
36+
37+
AMDGPUVariadicMCExpr(VariadicKind Kind, ArrayRef<const MCExpr *> Args,
38+
MCContext &Ctx);
39+
~AMDGPUVariadicMCExpr();
40+
41+
public:
42+
static const AMDGPUVariadicMCExpr *
43+
create(VariadicKind Kind, ArrayRef<const MCExpr *> Args, MCContext &Ctx);
44+
45+
static const AMDGPUVariadicMCExpr *createOr(ArrayRef<const MCExpr *> Args,
46+
MCContext &Ctx) {
47+
return create(VariadicKind::AGVK_Or, Args, Ctx);
48+
}
49+
50+
static const AMDGPUVariadicMCExpr *createMax(ArrayRef<const MCExpr *> Args,
51+
MCContext &Ctx) {
52+
return create(VariadicKind::AGVK_Max, Args, Ctx);
53+
}
54+
55+
VariadicKind getKind() const { return Kind; }
56+
const MCExpr *getSubExpr(size_t Index) const;
57+
58+
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
59+
bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
60+
const MCFixup *Fixup) const override;
61+
void visitUsedExpr(MCStreamer &Streamer) const override;
62+
MCFragment *findAssociatedFragment() const override;
63+
void fixELFSymbolsInTLSFixups(MCAssembler &) const override{};
64+
65+
static bool classof(const MCExpr *E) {
66+
return E->getKind() == MCExpr::Target;
67+
}
68+
};
69+
70+
} // end namespace llvm
71+
72+
#endif // LLVM_LIB_TARGET_AMDGPU_MCTARGETDESC_AMDGPUMCEXPR_H

llvm/lib/Target/AMDGPU/MCTargetDesc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ add_llvm_component_library(LLVMAMDGPUDesc
55
AMDGPUInstPrinter.cpp
66
AMDGPUMCAsmInfo.cpp
77
AMDGPUMCCodeEmitter.cpp
8+
AMDGPUMCExpr.cpp
89
AMDGPUMCTargetDesc.cpp
910
AMDGPUTargetStreamer.cpp
1011
R600InstPrinter.cpp

0 commit comments

Comments
 (0)