1f7bebc19SJanek van Oirschot //===- AMDGPUMCExpr.cpp - AMDGPU specific MC expression classes -----------===// 2f7bebc19SJanek van Oirschot // 3f7bebc19SJanek van Oirschot // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f7bebc19SJanek van Oirschot // See https://llvm.org/LICENSE.txt for license information. 5f7bebc19SJanek van Oirschot // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f7bebc19SJanek van Oirschot // 7f7bebc19SJanek van Oirschot //===----------------------------------------------------------------------===// 8f7bebc19SJanek van Oirschot 9f7bebc19SJanek van Oirschot #include "AMDGPUMCExpr.h" 10d86b68afSJanek van Oirschot #include "GCNSubtarget.h" 11d86b68afSJanek van Oirschot #include "Utils/AMDGPUBaseInfo.h" 12d86b68afSJanek van Oirschot #include "llvm/IR/Function.h" 13bfce1aaeSJanek van Oirschot #include "llvm/MC/MCAsmInfo.h" 14f22af401SFangrui Song #include "llvm/MC/MCAssembler.h" 15f7bebc19SJanek van Oirschot #include "llvm/MC/MCContext.h" 16f7bebc19SJanek van Oirschot #include "llvm/MC/MCStreamer.h" 17f7bebc19SJanek van Oirschot #include "llvm/MC/MCSymbol.h" 18f7bebc19SJanek van Oirschot #include "llvm/MC/MCValue.h" 19bfce1aaeSJanek van Oirschot #include "llvm/Support/KnownBits.h" 20f7bebc19SJanek van Oirschot #include "llvm/Support/raw_ostream.h" 21f7bebc19SJanek van Oirschot #include <optional> 22f7bebc19SJanek van Oirschot 23f7bebc19SJanek van Oirschot using namespace llvm; 24d86b68afSJanek van Oirschot using namespace llvm::AMDGPU; 25f7bebc19SJanek van Oirschot 2613ed349cSIvan Kosarev AMDGPUMCExpr::AMDGPUMCExpr(VariantKind Kind, ArrayRef<const MCExpr *> Args, 27f7bebc19SJanek van Oirschot MCContext &Ctx) 28f7bebc19SJanek van Oirschot : Kind(Kind), Ctx(Ctx) { 29f7bebc19SJanek van Oirschot assert(Args.size() >= 1 && "Needs a minimum of one expression."); 3013ed349cSIvan Kosarev assert(Kind != AGVK_None && "Cannot construct AMDGPUMCExpr of kind none."); 31f7bebc19SJanek van Oirschot 32f7bebc19SJanek van Oirschot // Allocating the variadic arguments through the same allocation mechanism 33f7bebc19SJanek van Oirschot // that the object itself is allocated with so they end up in the same memory. 34f7bebc19SJanek van Oirschot // 35f7bebc19SJanek van Oirschot // Will result in an asan failure if allocated on the heap through standard 36f7bebc19SJanek van Oirschot // allocation (e.g., through SmallVector's grow). 37f7bebc19SJanek van Oirschot RawArgs = static_cast<const MCExpr **>( 38f7bebc19SJanek van Oirschot Ctx.allocate(sizeof(const MCExpr *) * Args.size())); 39f7bebc19SJanek van Oirschot std::uninitialized_copy(Args.begin(), Args.end(), RawArgs); 40f7bebc19SJanek van Oirschot this->Args = ArrayRef<const MCExpr *>(RawArgs, Args.size()); 41f7bebc19SJanek van Oirschot } 42f7bebc19SJanek van Oirschot 4313ed349cSIvan Kosarev AMDGPUMCExpr::~AMDGPUMCExpr() { Ctx.deallocate(RawArgs); } 44f7bebc19SJanek van Oirschot 4513ed349cSIvan Kosarev const AMDGPUMCExpr *AMDGPUMCExpr::create(VariantKind Kind, 4613ed349cSIvan Kosarev ArrayRef<const MCExpr *> Args, 47f7bebc19SJanek van Oirschot MCContext &Ctx) { 4813ed349cSIvan Kosarev return new (Ctx) AMDGPUMCExpr(Kind, Args, Ctx); 49f7bebc19SJanek van Oirschot } 50f7bebc19SJanek van Oirschot 5113ed349cSIvan Kosarev const MCExpr *AMDGPUMCExpr::getSubExpr(size_t Index) const { 5213ed349cSIvan Kosarev assert(Index < Args.size() && "Indexing out of bounds AMDGPUMCExpr sub-expr"); 53f7bebc19SJanek van Oirschot return Args[Index]; 54f7bebc19SJanek van Oirschot } 55f7bebc19SJanek van Oirschot 5613ed349cSIvan Kosarev void AMDGPUMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { 57f7bebc19SJanek van Oirschot switch (Kind) { 58f7bebc19SJanek van Oirschot default: 5913ed349cSIvan Kosarev llvm_unreachable("Unknown AMDGPUMCExpr kind."); 60f7bebc19SJanek van Oirschot case AGVK_Or: 61f7bebc19SJanek van Oirschot OS << "or("; 62f7bebc19SJanek van Oirschot break; 63f7bebc19SJanek van Oirschot case AGVK_Max: 64f7bebc19SJanek van Oirschot OS << "max("; 65f7bebc19SJanek van Oirschot break; 66d86b68afSJanek van Oirschot case AGVK_ExtraSGPRs: 67d86b68afSJanek van Oirschot OS << "extrasgprs("; 68d86b68afSJanek van Oirschot break; 69d86b68afSJanek van Oirschot case AGVK_TotalNumVGPRs: 70d86b68afSJanek van Oirschot OS << "totalnumvgprs("; 71d86b68afSJanek van Oirschot break; 72d86b68afSJanek van Oirschot case AGVK_AlignTo: 73d86b68afSJanek van Oirschot OS << "alignto("; 74d86b68afSJanek van Oirschot break; 75d86b68afSJanek van Oirschot case AGVK_Occupancy: 76d86b68afSJanek van Oirschot OS << "occupancy("; 77d86b68afSJanek van Oirschot break; 78f7bebc19SJanek van Oirschot } 798d13e7b8SJay Foad for (const auto *It = Args.begin(); It != Args.end(); ++It) { 80f7bebc19SJanek van Oirschot (*It)->print(OS, MAI, /*InParens=*/false); 81f7bebc19SJanek van Oirschot if ((It + 1) != Args.end()) 82f7bebc19SJanek van Oirschot OS << ", "; 83f7bebc19SJanek van Oirschot } 84f7bebc19SJanek van Oirschot OS << ')'; 85f7bebc19SJanek van Oirschot } 86f7bebc19SJanek van Oirschot 8713ed349cSIvan Kosarev static int64_t op(AMDGPUMCExpr::VariantKind Kind, int64_t Arg1, int64_t Arg2) { 88f7bebc19SJanek van Oirschot switch (Kind) { 89f7bebc19SJanek van Oirschot default: 9013ed349cSIvan Kosarev llvm_unreachable("Unknown AMDGPUMCExpr kind."); 9113ed349cSIvan Kosarev case AMDGPUMCExpr::AGVK_Max: 92f7bebc19SJanek van Oirschot return std::max(Arg1, Arg2); 9313ed349cSIvan Kosarev case AMDGPUMCExpr::AGVK_Or: 94f7bebc19SJanek van Oirschot return Arg1 | Arg2; 95f7bebc19SJanek van Oirschot } 96f7bebc19SJanek van Oirschot } 97f7bebc19SJanek van Oirschot 98f22af401SFangrui Song bool AMDGPUMCExpr::evaluateExtraSGPRs(MCValue &Res, const MCAssembler *Asm, 99d86b68afSJanek van Oirschot const MCFixup *Fixup) const { 100d86b68afSJanek van Oirschot auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { 101d86b68afSJanek van Oirschot MCValue MCVal; 102e25e8003SFangrui Song if (!Arg->evaluateAsRelocatable(MCVal, Asm, Fixup) || !MCVal.isAbsolute()) 103d86b68afSJanek van Oirschot return false; 104d86b68afSJanek van Oirschot 105d86b68afSJanek van Oirschot ConstantValue = MCVal.getConstant(); 106d86b68afSJanek van Oirschot return true; 107d86b68afSJanek van Oirschot }; 108d86b68afSJanek van Oirschot 109d86b68afSJanek van Oirschot assert(Args.size() == 3 && 11013ed349cSIvan Kosarev "AMDGPUMCExpr Argument count incorrect for ExtraSGPRs"); 111d86b68afSJanek van Oirschot const MCSubtargetInfo *STI = Ctx.getSubtargetInfo(); 112d86b68afSJanek van Oirschot uint64_t VCCUsed = 0, FlatScrUsed = 0, XNACKUsed = 0; 113d86b68afSJanek van Oirschot 114d86b68afSJanek van Oirschot bool Success = TryGetMCExprValue(Args[2], XNACKUsed); 115d86b68afSJanek van Oirschot 116d86b68afSJanek van Oirschot assert(Success && "Arguments 3 for ExtraSGPRs should be a known constant"); 117d86b68afSJanek van Oirschot if (!Success || !TryGetMCExprValue(Args[0], VCCUsed) || 118d86b68afSJanek van Oirschot !TryGetMCExprValue(Args[1], FlatScrUsed)) 119d86b68afSJanek van Oirschot return false; 120d86b68afSJanek van Oirschot 121d86b68afSJanek van Oirschot uint64_t ExtraSGPRs = IsaInfo::getNumExtraSGPRs( 122d86b68afSJanek van Oirschot STI, (bool)VCCUsed, (bool)FlatScrUsed, (bool)XNACKUsed); 123d86b68afSJanek van Oirschot Res = MCValue::get(ExtraSGPRs); 124d86b68afSJanek van Oirschot return true; 125d86b68afSJanek van Oirschot } 126d86b68afSJanek van Oirschot 127f22af401SFangrui Song bool AMDGPUMCExpr::evaluateTotalNumVGPR(MCValue &Res, const MCAssembler *Asm, 128d86b68afSJanek van Oirschot const MCFixup *Fixup) const { 129d86b68afSJanek van Oirschot auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { 130d86b68afSJanek van Oirschot MCValue MCVal; 131e25e8003SFangrui Song if (!Arg->evaluateAsRelocatable(MCVal, Asm, Fixup) || !MCVal.isAbsolute()) 132d86b68afSJanek van Oirschot return false; 133d86b68afSJanek van Oirschot 134d86b68afSJanek van Oirschot ConstantValue = MCVal.getConstant(); 135d86b68afSJanek van Oirschot return true; 136d86b68afSJanek van Oirschot }; 137d86b68afSJanek van Oirschot assert(Args.size() == 2 && 13813ed349cSIvan Kosarev "AMDGPUMCExpr Argument count incorrect for TotalNumVGPRs"); 139d86b68afSJanek van Oirschot const MCSubtargetInfo *STI = Ctx.getSubtargetInfo(); 140d86b68afSJanek van Oirschot uint64_t NumAGPR = 0, NumVGPR = 0; 141d86b68afSJanek van Oirschot 142d86b68afSJanek van Oirschot bool Has90AInsts = AMDGPU::isGFX90A(*STI); 143d86b68afSJanek van Oirschot 144d86b68afSJanek van Oirschot if (!TryGetMCExprValue(Args[0], NumAGPR) || 145d86b68afSJanek van Oirschot !TryGetMCExprValue(Args[1], NumVGPR)) 146d86b68afSJanek van Oirschot return false; 147d86b68afSJanek van Oirschot 148d86b68afSJanek van Oirschot uint64_t TotalNum = Has90AInsts && NumAGPR ? alignTo(NumVGPR, 4) + NumAGPR 149d86b68afSJanek van Oirschot : std::max(NumVGPR, NumAGPR); 150d86b68afSJanek van Oirschot Res = MCValue::get(TotalNum); 151d86b68afSJanek van Oirschot return true; 152d86b68afSJanek van Oirschot } 153d86b68afSJanek van Oirschot 154f22af401SFangrui Song bool AMDGPUMCExpr::evaluateAlignTo(MCValue &Res, const MCAssembler *Asm, 155d86b68afSJanek van Oirschot const MCFixup *Fixup) const { 156d86b68afSJanek van Oirschot auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { 157d86b68afSJanek van Oirschot MCValue MCVal; 158e25e8003SFangrui Song if (!Arg->evaluateAsRelocatable(MCVal, Asm, Fixup) || !MCVal.isAbsolute()) 159d86b68afSJanek van Oirschot return false; 160d86b68afSJanek van Oirschot 161d86b68afSJanek van Oirschot ConstantValue = MCVal.getConstant(); 162d86b68afSJanek van Oirschot return true; 163d86b68afSJanek van Oirschot }; 164d86b68afSJanek van Oirschot 165d86b68afSJanek van Oirschot assert(Args.size() == 2 && 16613ed349cSIvan Kosarev "AMDGPUMCExpr Argument count incorrect for AlignTo"); 167d86b68afSJanek van Oirschot uint64_t Value = 0, Align = 0; 168d86b68afSJanek van Oirschot if (!TryGetMCExprValue(Args[0], Value) || !TryGetMCExprValue(Args[1], Align)) 169d86b68afSJanek van Oirschot return false; 170d86b68afSJanek van Oirschot 171d86b68afSJanek van Oirschot Res = MCValue::get(alignTo(Value, Align)); 172d86b68afSJanek van Oirschot return true; 173d86b68afSJanek van Oirschot } 174d86b68afSJanek van Oirschot 175f22af401SFangrui Song bool AMDGPUMCExpr::evaluateOccupancy(MCValue &Res, const MCAssembler *Asm, 176d86b68afSJanek van Oirschot const MCFixup *Fixup) const { 177d86b68afSJanek van Oirschot auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { 178d86b68afSJanek van Oirschot MCValue MCVal; 179e25e8003SFangrui Song if (!Arg->evaluateAsRelocatable(MCVal, Asm, Fixup) || !MCVal.isAbsolute()) 180d86b68afSJanek van Oirschot return false; 181d86b68afSJanek van Oirschot 182d86b68afSJanek van Oirschot ConstantValue = MCVal.getConstant(); 183d86b68afSJanek van Oirschot return true; 184d86b68afSJanek van Oirschot }; 185d86b68afSJanek van Oirschot assert(Args.size() == 7 && 18613ed349cSIvan Kosarev "AMDGPUMCExpr Argument count incorrect for Occupancy"); 187d86b68afSJanek van Oirschot uint64_t InitOccupancy, MaxWaves, Granule, TargetTotalNumVGPRs, Generation, 188d86b68afSJanek van Oirschot NumSGPRs, NumVGPRs; 189d86b68afSJanek van Oirschot 190d86b68afSJanek van Oirschot bool Success = true; 191d86b68afSJanek van Oirschot Success &= TryGetMCExprValue(Args[0], MaxWaves); 192d86b68afSJanek van Oirschot Success &= TryGetMCExprValue(Args[1], Granule); 193d86b68afSJanek van Oirschot Success &= TryGetMCExprValue(Args[2], TargetTotalNumVGPRs); 194d86b68afSJanek van Oirschot Success &= TryGetMCExprValue(Args[3], Generation); 195d86b68afSJanek van Oirschot Success &= TryGetMCExprValue(Args[4], InitOccupancy); 196d86b68afSJanek van Oirschot 197d86b68afSJanek van Oirschot assert(Success && "Arguments 1 to 5 for Occupancy should be known constants"); 198d86b68afSJanek van Oirschot 199d86b68afSJanek van Oirschot if (!Success || !TryGetMCExprValue(Args[5], NumSGPRs) || 200d86b68afSJanek van Oirschot !TryGetMCExprValue(Args[6], NumVGPRs)) 201d86b68afSJanek van Oirschot return false; 202d86b68afSJanek van Oirschot 203d86b68afSJanek van Oirschot unsigned Occupancy = InitOccupancy; 204d86b68afSJanek van Oirschot if (NumSGPRs) 205d86b68afSJanek van Oirschot Occupancy = std::min( 206d86b68afSJanek van Oirschot Occupancy, IsaInfo::getOccupancyWithNumSGPRs( 207d86b68afSJanek van Oirschot NumSGPRs, MaxWaves, 208d86b68afSJanek van Oirschot static_cast<AMDGPUSubtarget::Generation>(Generation))); 209d86b68afSJanek van Oirschot if (NumVGPRs) 210d86b68afSJanek van Oirschot Occupancy = std::min(Occupancy, 211d86b68afSJanek van Oirschot IsaInfo::getNumWavesPerEUWithNumVGPRs( 212d86b68afSJanek van Oirschot NumVGPRs, Granule, MaxWaves, TargetTotalNumVGPRs)); 213d86b68afSJanek van Oirschot 214d86b68afSJanek van Oirschot Res = MCValue::get(Occupancy); 215d86b68afSJanek van Oirschot return true; 216d86b68afSJanek van Oirschot } 217d86b68afSJanek van Oirschot 21813ed349cSIvan Kosarev bool AMDGPUMCExpr::evaluateAsRelocatableImpl(MCValue &Res, 219e25e8003SFangrui Song const MCAssembler *Asm, 22013ed349cSIvan Kosarev const MCFixup *Fixup) const { 221f7bebc19SJanek van Oirschot std::optional<int64_t> Total; 222d86b68afSJanek van Oirschot switch (Kind) { 223d86b68afSJanek van Oirschot default: 224d86b68afSJanek van Oirschot break; 225d86b68afSJanek van Oirschot case AGVK_ExtraSGPRs: 226f22af401SFangrui Song return evaluateExtraSGPRs(Res, Asm, Fixup); 227d86b68afSJanek van Oirschot case AGVK_AlignTo: 228f22af401SFangrui Song return evaluateAlignTo(Res, Asm, Fixup); 229d86b68afSJanek van Oirschot case AGVK_TotalNumVGPRs: 230f22af401SFangrui Song return evaluateTotalNumVGPR(Res, Asm, Fixup); 231d86b68afSJanek van Oirschot case AGVK_Occupancy: 232f22af401SFangrui Song return evaluateOccupancy(Res, Asm, Fixup); 233d86b68afSJanek van Oirschot } 234d86b68afSJanek van Oirschot 235f7bebc19SJanek van Oirschot for (const MCExpr *Arg : Args) { 236f7bebc19SJanek van Oirschot MCValue ArgRes; 237e25e8003SFangrui Song if (!Arg->evaluateAsRelocatable(ArgRes, Asm, Fixup) || !ArgRes.isAbsolute()) 238f7bebc19SJanek van Oirschot return false; 239f7bebc19SJanek van Oirschot 240f7bebc19SJanek van Oirschot if (!Total.has_value()) 241f7bebc19SJanek van Oirschot Total = ArgRes.getConstant(); 242f7bebc19SJanek van Oirschot Total = op(Kind, *Total, ArgRes.getConstant()); 243f7bebc19SJanek van Oirschot } 244f7bebc19SJanek van Oirschot 245f7bebc19SJanek van Oirschot Res = MCValue::get(*Total); 246f7bebc19SJanek van Oirschot return true; 247f7bebc19SJanek van Oirschot } 248f7bebc19SJanek van Oirschot 24913ed349cSIvan Kosarev void AMDGPUMCExpr::visitUsedExpr(MCStreamer &Streamer) const { 250f7bebc19SJanek van Oirschot for (const MCExpr *Arg : Args) 251f7bebc19SJanek van Oirschot Streamer.visitUsedExpr(*Arg); 252f7bebc19SJanek van Oirschot } 253f7bebc19SJanek van Oirschot 25413ed349cSIvan Kosarev MCFragment *AMDGPUMCExpr::findAssociatedFragment() const { 255f7bebc19SJanek van Oirschot for (const MCExpr *Arg : Args) { 256f7bebc19SJanek van Oirschot if (Arg->findAssociatedFragment()) 257f7bebc19SJanek van Oirschot return Arg->findAssociatedFragment(); 258f7bebc19SJanek van Oirschot } 259f7bebc19SJanek van Oirschot return nullptr; 260f7bebc19SJanek van Oirschot } 261d86b68afSJanek van Oirschot 262d86b68afSJanek van Oirschot /// Allow delayed MCExpr resolve of ExtraSGPRs (in case VCCUsed or FlatScrUsed 263d86b68afSJanek van Oirschot /// are unresolvable but needed for further MCExprs). Derived from 264d86b68afSJanek van Oirschot /// implementation of IsaInfo::getNumExtraSGPRs in AMDGPUBaseInfo.cpp. 265d86b68afSJanek van Oirschot /// 26613ed349cSIvan Kosarev const AMDGPUMCExpr *AMDGPUMCExpr::createExtraSGPRs(const MCExpr *VCCUsed, 267d86b68afSJanek van Oirschot const MCExpr *FlatScrUsed, 26813ed349cSIvan Kosarev bool XNACKUsed, 26913ed349cSIvan Kosarev MCContext &Ctx) { 270d86b68afSJanek van Oirschot 271d86b68afSJanek van Oirschot return create(AGVK_ExtraSGPRs, 272d86b68afSJanek van Oirschot {VCCUsed, FlatScrUsed, MCConstantExpr::create(XNACKUsed, Ctx)}, 273d86b68afSJanek van Oirschot Ctx); 274d86b68afSJanek van Oirschot } 275d86b68afSJanek van Oirschot 27613ed349cSIvan Kosarev const AMDGPUMCExpr *AMDGPUMCExpr::createTotalNumVGPR(const MCExpr *NumAGPR, 27713ed349cSIvan Kosarev const MCExpr *NumVGPR, 27813ed349cSIvan Kosarev MCContext &Ctx) { 279d86b68afSJanek van Oirschot return create(AGVK_TotalNumVGPRs, {NumAGPR, NumVGPR}, Ctx); 280d86b68afSJanek van Oirschot } 281d86b68afSJanek van Oirschot 282d86b68afSJanek van Oirschot /// Mimics GCNSubtarget::computeOccupancy for MCExpr. 283d86b68afSJanek van Oirschot /// 284d86b68afSJanek van Oirschot /// Remove dependency on GCNSubtarget and depend only only the necessary values 285d86b68afSJanek van Oirschot /// for said occupancy computation. Should match computeOccupancy implementation 286d86b68afSJanek van Oirschot /// without passing \p STM on. 28713ed349cSIvan Kosarev const AMDGPUMCExpr *AMDGPUMCExpr::createOccupancy(unsigned InitOcc, 28813ed349cSIvan Kosarev const MCExpr *NumSGPRs, 289d86b68afSJanek van Oirschot const MCExpr *NumVGPRs, 29013ed349cSIvan Kosarev const GCNSubtarget &STM, 29113ed349cSIvan Kosarev MCContext &Ctx) { 292d86b68afSJanek van Oirschot unsigned MaxWaves = IsaInfo::getMaxWavesPerEU(&STM); 293d86b68afSJanek van Oirschot unsigned Granule = IsaInfo::getVGPRAllocGranule(&STM); 294d86b68afSJanek van Oirschot unsigned TargetTotalNumVGPRs = IsaInfo::getTotalNumVGPRs(&STM); 295d86b68afSJanek van Oirschot unsigned Generation = STM.getGeneration(); 296d86b68afSJanek van Oirschot 297d86b68afSJanek van Oirschot auto CreateExpr = [&Ctx](unsigned Value) { 298d86b68afSJanek van Oirschot return MCConstantExpr::create(Value, Ctx); 299d86b68afSJanek van Oirschot }; 300d86b68afSJanek van Oirschot 301d86b68afSJanek van Oirschot return create(AGVK_Occupancy, 302d86b68afSJanek van Oirschot {CreateExpr(MaxWaves), CreateExpr(Granule), 303d86b68afSJanek van Oirschot CreateExpr(TargetTotalNumVGPRs), CreateExpr(Generation), 304d86b68afSJanek van Oirschot CreateExpr(InitOcc), NumSGPRs, NumVGPRs}, 305d86b68afSJanek van Oirschot Ctx); 306d86b68afSJanek van Oirschot } 307bfce1aaeSJanek van Oirschot 308*bd9145c8SJanek van Oirschot bool AMDGPUMCExpr::isSymbolUsedInExpression(const MCSymbol *Sym) const { 309*bd9145c8SJanek van Oirschot for (const MCExpr *E : getArgs()) { 310*bd9145c8SJanek van Oirschot if (E->isSymbolUsedInExpression(Sym)) 311*bd9145c8SJanek van Oirschot return true; 312*bd9145c8SJanek van Oirschot } 313*bd9145c8SJanek van Oirschot return false; 314*bd9145c8SJanek van Oirschot } 315*bd9145c8SJanek van Oirschot 316bfce1aaeSJanek van Oirschot static KnownBits fromOptionalToKnownBits(std::optional<bool> CompareResult) { 317bfce1aaeSJanek van Oirschot static constexpr unsigned BitWidth = 64; 318bfce1aaeSJanek van Oirschot const APInt True(BitWidth, 1); 319bfce1aaeSJanek van Oirschot const APInt False(BitWidth, 0); 320bfce1aaeSJanek van Oirschot if (CompareResult) { 321bfce1aaeSJanek van Oirschot return *CompareResult ? KnownBits::makeConstant(True) 322bfce1aaeSJanek van Oirschot : KnownBits::makeConstant(False); 323bfce1aaeSJanek van Oirschot } 324bfce1aaeSJanek van Oirschot 325bfce1aaeSJanek van Oirschot KnownBits UnknownBool(/*BitWidth=*/1); 326bfce1aaeSJanek van Oirschot return UnknownBool.zext(BitWidth); 327bfce1aaeSJanek van Oirschot } 328bfce1aaeSJanek van Oirschot 329bfce1aaeSJanek van Oirschot using KnownBitsMap = DenseMap<const MCExpr *, KnownBits>; 330bfce1aaeSJanek van Oirschot static void knownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM, 331bfce1aaeSJanek van Oirschot unsigned Depth = 0); 332bfce1aaeSJanek van Oirschot 333bfce1aaeSJanek van Oirschot static void binaryOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM, 334bfce1aaeSJanek van Oirschot unsigned Depth) { 335bfce1aaeSJanek van Oirschot static constexpr unsigned BitWidth = 64; 336bfce1aaeSJanek van Oirschot const MCBinaryExpr *BExpr = cast<MCBinaryExpr>(Expr); 337bfce1aaeSJanek van Oirschot const MCExpr *LHS = BExpr->getLHS(); 338bfce1aaeSJanek van Oirschot const MCExpr *RHS = BExpr->getRHS(); 339bfce1aaeSJanek van Oirschot 340bfce1aaeSJanek van Oirschot knownBitsMapHelper(LHS, KBM, Depth + 1); 341bfce1aaeSJanek van Oirschot knownBitsMapHelper(RHS, KBM, Depth + 1); 342bfce1aaeSJanek van Oirschot KnownBits LHSKnown = KBM[LHS]; 343bfce1aaeSJanek van Oirschot KnownBits RHSKnown = KBM[RHS]; 344bfce1aaeSJanek van Oirschot 345bfce1aaeSJanek van Oirschot switch (BExpr->getOpcode()) { 346bfce1aaeSJanek van Oirschot default: 347bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits(BitWidth); 348bfce1aaeSJanek van Oirschot return; 349bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Add: 350bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::add(LHSKnown, RHSKnown); 351bfce1aaeSJanek van Oirschot return; 352bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::And: 353bfce1aaeSJanek van Oirschot KBM[Expr] = LHSKnown & RHSKnown; 354bfce1aaeSJanek van Oirschot return; 355bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Div: 356bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::sdiv(LHSKnown, RHSKnown); 357bfce1aaeSJanek van Oirschot return; 358bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::EQ: { 359bfce1aaeSJanek van Oirschot std::optional<bool> CompareRes = KnownBits::eq(LHSKnown, RHSKnown); 360bfce1aaeSJanek van Oirschot KBM[Expr] = fromOptionalToKnownBits(CompareRes); 361bfce1aaeSJanek van Oirschot return; 362bfce1aaeSJanek van Oirschot } 363bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::NE: { 364bfce1aaeSJanek van Oirschot std::optional<bool> CompareRes = KnownBits::ne(LHSKnown, RHSKnown); 365bfce1aaeSJanek van Oirschot KBM[Expr] = fromOptionalToKnownBits(CompareRes); 366bfce1aaeSJanek van Oirschot return; 367bfce1aaeSJanek van Oirschot } 368bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::GT: { 369bfce1aaeSJanek van Oirschot std::optional<bool> CompareRes = KnownBits::sgt(LHSKnown, RHSKnown); 370bfce1aaeSJanek van Oirschot KBM[Expr] = fromOptionalToKnownBits(CompareRes); 371bfce1aaeSJanek van Oirschot return; 372bfce1aaeSJanek van Oirschot } 373bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::GTE: { 374bfce1aaeSJanek van Oirschot std::optional<bool> CompareRes = KnownBits::sge(LHSKnown, RHSKnown); 375bfce1aaeSJanek van Oirschot KBM[Expr] = fromOptionalToKnownBits(CompareRes); 376bfce1aaeSJanek van Oirschot return; 377bfce1aaeSJanek van Oirschot } 378bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::LAnd: { 379bfce1aaeSJanek van Oirschot std::optional<bool> CompareRes; 380bfce1aaeSJanek van Oirschot const APInt False(BitWidth, 0); 381bfce1aaeSJanek van Oirschot std::optional<bool> LHSBool = 382bfce1aaeSJanek van Oirschot KnownBits::ne(LHSKnown, KnownBits::makeConstant(False)); 383bfce1aaeSJanek van Oirschot std::optional<bool> RHSBool = 384bfce1aaeSJanek van Oirschot KnownBits::ne(RHSKnown, KnownBits::makeConstant(False)); 385bfce1aaeSJanek van Oirschot if (LHSBool && RHSBool) 386bfce1aaeSJanek van Oirschot CompareRes = *LHSBool && *RHSBool; 387bfce1aaeSJanek van Oirschot KBM[Expr] = fromOptionalToKnownBits(CompareRes); 388bfce1aaeSJanek van Oirschot return; 389bfce1aaeSJanek van Oirschot } 390bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::LOr: { 391bfce1aaeSJanek van Oirschot const APInt False(BitWidth, 0); 392bfce1aaeSJanek van Oirschot KnownBits Bits = LHSKnown | RHSKnown; 393bfce1aaeSJanek van Oirschot std::optional<bool> CompareRes = 394bfce1aaeSJanek van Oirschot KnownBits::ne(Bits, KnownBits::makeConstant(False)); 395bfce1aaeSJanek van Oirschot KBM[Expr] = fromOptionalToKnownBits(CompareRes); 396bfce1aaeSJanek van Oirschot return; 397bfce1aaeSJanek van Oirschot } 398bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::LT: { 399bfce1aaeSJanek van Oirschot std::optional<bool> CompareRes = KnownBits::slt(LHSKnown, RHSKnown); 400bfce1aaeSJanek van Oirschot KBM[Expr] = fromOptionalToKnownBits(CompareRes); 401bfce1aaeSJanek van Oirschot return; 402bfce1aaeSJanek van Oirschot } 403bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::LTE: { 404bfce1aaeSJanek van Oirschot std::optional<bool> CompareRes = KnownBits::sle(LHSKnown, RHSKnown); 405bfce1aaeSJanek van Oirschot KBM[Expr] = fromOptionalToKnownBits(CompareRes); 406bfce1aaeSJanek van Oirschot return; 407bfce1aaeSJanek van Oirschot } 408bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Mod: 409bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::srem(LHSKnown, RHSKnown); 410bfce1aaeSJanek van Oirschot return; 411bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Mul: 412bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::mul(LHSKnown, RHSKnown); 413bfce1aaeSJanek van Oirschot return; 414bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Or: 415bfce1aaeSJanek van Oirschot KBM[Expr] = LHSKnown | RHSKnown; 416bfce1aaeSJanek van Oirschot return; 417bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Shl: 418bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::shl(LHSKnown, RHSKnown); 419bfce1aaeSJanek van Oirschot return; 420bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::AShr: 421bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::ashr(LHSKnown, RHSKnown); 422bfce1aaeSJanek van Oirschot return; 423bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::LShr: 424bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::lshr(LHSKnown, RHSKnown); 425bfce1aaeSJanek van Oirschot return; 426bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Sub: 427bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::sub(LHSKnown, RHSKnown); 428bfce1aaeSJanek van Oirschot return; 429bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Xor: 430bfce1aaeSJanek van Oirschot KBM[Expr] = LHSKnown ^ RHSKnown; 431bfce1aaeSJanek van Oirschot return; 432bfce1aaeSJanek van Oirschot } 433bfce1aaeSJanek van Oirschot } 434bfce1aaeSJanek van Oirschot 435bfce1aaeSJanek van Oirschot static void unaryOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM, 436bfce1aaeSJanek van Oirschot unsigned Depth) { 437bfce1aaeSJanek van Oirschot static constexpr unsigned BitWidth = 64; 438bfce1aaeSJanek van Oirschot const MCUnaryExpr *UExpr = cast<MCUnaryExpr>(Expr); 439bfce1aaeSJanek van Oirschot knownBitsMapHelper(UExpr->getSubExpr(), KBM, Depth + 1); 440bfce1aaeSJanek van Oirschot KnownBits KB = KBM[UExpr->getSubExpr()]; 441bfce1aaeSJanek van Oirschot 442bfce1aaeSJanek van Oirschot switch (UExpr->getOpcode()) { 443bfce1aaeSJanek van Oirschot default: 444bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits(BitWidth); 445bfce1aaeSJanek van Oirschot return; 446bfce1aaeSJanek van Oirschot case MCUnaryExpr::Opcode::Minus: { 447bfce1aaeSJanek van Oirschot KB.makeNegative(); 448bfce1aaeSJanek van Oirschot KBM[Expr] = KB; 449bfce1aaeSJanek van Oirschot return; 450bfce1aaeSJanek van Oirschot } 451bfce1aaeSJanek van Oirschot case MCUnaryExpr::Opcode::Not: { 452bfce1aaeSJanek van Oirschot KnownBits AllOnes(BitWidth); 453bfce1aaeSJanek van Oirschot AllOnes.setAllOnes(); 454bfce1aaeSJanek van Oirschot KBM[Expr] = KB ^ AllOnes; 455bfce1aaeSJanek van Oirschot return; 456bfce1aaeSJanek van Oirschot } 457bfce1aaeSJanek van Oirschot case MCUnaryExpr::Opcode::Plus: { 458bfce1aaeSJanek van Oirschot KB.makeNonNegative(); 459bfce1aaeSJanek van Oirschot KBM[Expr] = KB; 460bfce1aaeSJanek van Oirschot return; 461bfce1aaeSJanek van Oirschot } 462bfce1aaeSJanek van Oirschot } 463bfce1aaeSJanek van Oirschot } 464bfce1aaeSJanek van Oirschot 465bfce1aaeSJanek van Oirschot static void targetOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM, 466bfce1aaeSJanek van Oirschot unsigned Depth) { 467bfce1aaeSJanek van Oirschot static constexpr unsigned BitWidth = 64; 468bfce1aaeSJanek van Oirschot const AMDGPUMCExpr *AGVK = cast<AMDGPUMCExpr>(Expr); 469bfce1aaeSJanek van Oirschot 470bfce1aaeSJanek van Oirschot switch (AGVK->getKind()) { 471bfce1aaeSJanek van Oirschot default: 472bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits(BitWidth); 473bfce1aaeSJanek van Oirschot return; 474bfce1aaeSJanek van Oirschot case AMDGPUMCExpr::VariantKind::AGVK_Or: { 475bfce1aaeSJanek van Oirschot knownBitsMapHelper(AGVK->getSubExpr(0), KBM, Depth + 1); 476bfce1aaeSJanek van Oirschot KnownBits KB = KBM[AGVK->getSubExpr(0)]; 477bfce1aaeSJanek van Oirschot for (const MCExpr *Arg : AGVK->getArgs()) { 478bfce1aaeSJanek van Oirschot knownBitsMapHelper(Arg, KBM, Depth + 1); 479bfce1aaeSJanek van Oirschot KB |= KBM[Arg]; 480bfce1aaeSJanek van Oirschot } 481bfce1aaeSJanek van Oirschot KBM[Expr] = KB; 482bfce1aaeSJanek van Oirschot return; 483bfce1aaeSJanek van Oirschot } 484bfce1aaeSJanek van Oirschot case AMDGPUMCExpr::VariantKind::AGVK_Max: { 485bfce1aaeSJanek van Oirschot knownBitsMapHelper(AGVK->getSubExpr(0), KBM, Depth + 1); 486bfce1aaeSJanek van Oirschot KnownBits KB = KBM[AGVK->getSubExpr(0)]; 487bfce1aaeSJanek van Oirschot for (const MCExpr *Arg : AGVK->getArgs()) { 488bfce1aaeSJanek van Oirschot knownBitsMapHelper(Arg, KBM, Depth + 1); 489bfce1aaeSJanek van Oirschot KB = KnownBits::umax(KB, KBM[Arg]); 490bfce1aaeSJanek van Oirschot } 491bfce1aaeSJanek van Oirschot KBM[Expr] = KB; 492bfce1aaeSJanek van Oirschot return; 493bfce1aaeSJanek van Oirschot } 494bfce1aaeSJanek van Oirschot case AMDGPUMCExpr::VariantKind::AGVK_ExtraSGPRs: 495bfce1aaeSJanek van Oirschot case AMDGPUMCExpr::VariantKind::AGVK_TotalNumVGPRs: 496bfce1aaeSJanek van Oirschot case AMDGPUMCExpr::VariantKind::AGVK_AlignTo: 497bfce1aaeSJanek van Oirschot case AMDGPUMCExpr::VariantKind::AGVK_Occupancy: { 498bfce1aaeSJanek van Oirschot int64_t Val; 499bfce1aaeSJanek van Oirschot if (AGVK->evaluateAsAbsolute(Val)) { 500bfce1aaeSJanek van Oirschot APInt APValue(BitWidth, Val); 501bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::makeConstant(APValue); 502bfce1aaeSJanek van Oirschot return; 503bfce1aaeSJanek van Oirschot } 504bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits(BitWidth); 505bfce1aaeSJanek van Oirschot return; 506bfce1aaeSJanek van Oirschot } 507bfce1aaeSJanek van Oirschot } 508bfce1aaeSJanek van Oirschot } 509bfce1aaeSJanek van Oirschot 510bfce1aaeSJanek van Oirschot static void knownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM, 511bfce1aaeSJanek van Oirschot unsigned Depth) { 512bfce1aaeSJanek van Oirschot static constexpr unsigned BitWidth = 64; 513bfce1aaeSJanek van Oirschot 514bfce1aaeSJanek van Oirschot int64_t Val; 515bfce1aaeSJanek van Oirschot if (Expr->evaluateAsAbsolute(Val)) { 516bfce1aaeSJanek van Oirschot APInt APValue(BitWidth, Val, /*isSigned=*/true); 517bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::makeConstant(APValue); 518bfce1aaeSJanek van Oirschot return; 519bfce1aaeSJanek van Oirschot } 520bfce1aaeSJanek van Oirschot 521bfce1aaeSJanek van Oirschot if (Depth == 16) { 522bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits(BitWidth); 523bfce1aaeSJanek van Oirschot return; 524bfce1aaeSJanek van Oirschot } 525bfce1aaeSJanek van Oirschot 526bfce1aaeSJanek van Oirschot switch (Expr->getKind()) { 527bfce1aaeSJanek van Oirschot case MCExpr::ExprKind::Binary: { 528bfce1aaeSJanek van Oirschot binaryOpKnownBitsMapHelper(Expr, KBM, Depth); 529bfce1aaeSJanek van Oirschot return; 530bfce1aaeSJanek van Oirschot } 531bfce1aaeSJanek van Oirschot case MCExpr::ExprKind::Constant: { 532bfce1aaeSJanek van Oirschot const MCConstantExpr *CE = cast<MCConstantExpr>(Expr); 533bfce1aaeSJanek van Oirschot APInt APValue(BitWidth, CE->getValue(), /*isSigned=*/true); 534bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits::makeConstant(APValue); 535bfce1aaeSJanek van Oirschot return; 536bfce1aaeSJanek van Oirschot } 537bfce1aaeSJanek van Oirschot case MCExpr::ExprKind::SymbolRef: { 538bfce1aaeSJanek van Oirschot const MCSymbolRefExpr *RExpr = cast<MCSymbolRefExpr>(Expr); 539bfce1aaeSJanek van Oirschot const MCSymbol &Sym = RExpr->getSymbol(); 540bfce1aaeSJanek van Oirschot if (!Sym.isVariable()) { 541bfce1aaeSJanek van Oirschot KBM[Expr] = KnownBits(BitWidth); 542bfce1aaeSJanek van Oirschot return; 543bfce1aaeSJanek van Oirschot } 544bfce1aaeSJanek van Oirschot 545bfce1aaeSJanek van Oirschot // Variable value retrieval is not for actual use but only for knownbits 546bfce1aaeSJanek van Oirschot // analysis. 547a18826d7SJanek van Oirschot const MCExpr *SymVal = Sym.getVariableValue(/*setUsed=*/false); 548a18826d7SJanek van Oirschot knownBitsMapHelper(SymVal, KBM, Depth + 1); 549a18826d7SJanek van Oirschot 550a18826d7SJanek van Oirschot // Explicitly copy-construct so that there exists a local KnownBits in case 551a18826d7SJanek van Oirschot // KBM[SymVal] gets invalidated after a potential growth through KBM[Expr]. 552a18826d7SJanek van Oirschot KBM[Expr] = KnownBits(KBM[SymVal]); 553bfce1aaeSJanek van Oirschot return; 554bfce1aaeSJanek van Oirschot } 555bfce1aaeSJanek van Oirschot case MCExpr::ExprKind::Unary: { 556bfce1aaeSJanek van Oirschot unaryOpKnownBitsMapHelper(Expr, KBM, Depth); 557bfce1aaeSJanek van Oirschot return; 558bfce1aaeSJanek van Oirschot } 559bfce1aaeSJanek van Oirschot case MCExpr::ExprKind::Target: { 560bfce1aaeSJanek van Oirschot targetOpKnownBitsMapHelper(Expr, KBM, Depth); 561bfce1aaeSJanek van Oirschot return; 562bfce1aaeSJanek van Oirschot } 563bfce1aaeSJanek van Oirschot } 564bfce1aaeSJanek van Oirschot } 565bfce1aaeSJanek van Oirschot 566bfce1aaeSJanek van Oirschot static const MCExpr *tryFoldHelper(const MCExpr *Expr, KnownBitsMap &KBM, 567bfce1aaeSJanek van Oirschot MCContext &Ctx) { 568bfce1aaeSJanek van Oirschot if (!KBM.count(Expr)) 569bfce1aaeSJanek van Oirschot return Expr; 570bfce1aaeSJanek van Oirschot 571bfce1aaeSJanek van Oirschot auto ValueCheckKnownBits = [](KnownBits &KB, unsigned Value) -> bool { 572bfce1aaeSJanek van Oirschot if (!KB.isConstant()) 573bfce1aaeSJanek van Oirschot return false; 574bfce1aaeSJanek van Oirschot 575bfce1aaeSJanek van Oirschot return Value == KB.getConstant(); 576bfce1aaeSJanek van Oirschot }; 577bfce1aaeSJanek van Oirschot 578bfce1aaeSJanek van Oirschot if (Expr->getKind() == MCExpr::ExprKind::Constant) 579bfce1aaeSJanek van Oirschot return Expr; 580bfce1aaeSJanek van Oirschot 581bfce1aaeSJanek van Oirschot // Resolving unary operations to constants may make the value more ambiguous. 582bfce1aaeSJanek van Oirschot // For example, `~62` becomes `-63`; however, to me it's more ambiguous if a 583bfce1aaeSJanek van Oirschot // bit mask value is represented through a negative number. 584bfce1aaeSJanek van Oirschot if (Expr->getKind() != MCExpr::ExprKind::Unary) { 585bfce1aaeSJanek van Oirschot if (KBM[Expr].isConstant()) { 586bfce1aaeSJanek van Oirschot APInt ConstVal = KBM[Expr].getConstant(); 587bfce1aaeSJanek van Oirschot return MCConstantExpr::create(ConstVal.getSExtValue(), Ctx); 588bfce1aaeSJanek van Oirschot } 589bfce1aaeSJanek van Oirschot 590bfce1aaeSJanek van Oirschot int64_t EvalValue; 591bfce1aaeSJanek van Oirschot if (Expr->evaluateAsAbsolute(EvalValue)) 592bfce1aaeSJanek van Oirschot return MCConstantExpr::create(EvalValue, Ctx); 593bfce1aaeSJanek van Oirschot } 594bfce1aaeSJanek van Oirschot 595bfce1aaeSJanek van Oirschot switch (Expr->getKind()) { 596bfce1aaeSJanek van Oirschot default: 597bfce1aaeSJanek van Oirschot return Expr; 598bfce1aaeSJanek van Oirschot case MCExpr::ExprKind::Binary: { 599bfce1aaeSJanek van Oirschot const MCBinaryExpr *BExpr = cast<MCBinaryExpr>(Expr); 600bfce1aaeSJanek van Oirschot const MCExpr *LHS = BExpr->getLHS(); 601bfce1aaeSJanek van Oirschot const MCExpr *RHS = BExpr->getRHS(); 602bfce1aaeSJanek van Oirschot 603bfce1aaeSJanek van Oirschot switch (BExpr->getOpcode()) { 604bfce1aaeSJanek van Oirschot default: 605bfce1aaeSJanek van Oirschot return Expr; 606bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Sub: { 607bfce1aaeSJanek van Oirschot if (ValueCheckKnownBits(KBM[RHS], 0)) 608bfce1aaeSJanek van Oirschot return tryFoldHelper(LHS, KBM, Ctx); 609bfce1aaeSJanek van Oirschot break; 610bfce1aaeSJanek van Oirschot } 611bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Add: 612bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Or: { 613bfce1aaeSJanek van Oirschot if (ValueCheckKnownBits(KBM[LHS], 0)) 614bfce1aaeSJanek van Oirschot return tryFoldHelper(RHS, KBM, Ctx); 615bfce1aaeSJanek van Oirschot if (ValueCheckKnownBits(KBM[RHS], 0)) 616bfce1aaeSJanek van Oirschot return tryFoldHelper(LHS, KBM, Ctx); 617bfce1aaeSJanek van Oirschot break; 618bfce1aaeSJanek van Oirschot } 619bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Mul: { 620bfce1aaeSJanek van Oirschot if (ValueCheckKnownBits(KBM[LHS], 1)) 621bfce1aaeSJanek van Oirschot return tryFoldHelper(RHS, KBM, Ctx); 622bfce1aaeSJanek van Oirschot if (ValueCheckKnownBits(KBM[RHS], 1)) 623bfce1aaeSJanek van Oirschot return tryFoldHelper(LHS, KBM, Ctx); 624bfce1aaeSJanek van Oirschot break; 625bfce1aaeSJanek van Oirschot } 626bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::Shl: 627bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::AShr: 628bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::LShr: { 629bfce1aaeSJanek van Oirschot if (ValueCheckKnownBits(KBM[RHS], 0)) 630bfce1aaeSJanek van Oirschot return tryFoldHelper(LHS, KBM, Ctx); 631bfce1aaeSJanek van Oirschot if (ValueCheckKnownBits(KBM[LHS], 0)) 632bfce1aaeSJanek van Oirschot return MCConstantExpr::create(0, Ctx); 633bfce1aaeSJanek van Oirschot break; 634bfce1aaeSJanek van Oirschot } 635bfce1aaeSJanek van Oirschot case MCBinaryExpr::Opcode::And: { 636bfce1aaeSJanek van Oirschot if (ValueCheckKnownBits(KBM[LHS], 0) || ValueCheckKnownBits(KBM[RHS], 0)) 637bfce1aaeSJanek van Oirschot return MCConstantExpr::create(0, Ctx); 638bfce1aaeSJanek van Oirschot break; 639bfce1aaeSJanek van Oirschot } 640bfce1aaeSJanek van Oirschot } 641bfce1aaeSJanek van Oirschot const MCExpr *NewLHS = tryFoldHelper(LHS, KBM, Ctx); 642bfce1aaeSJanek van Oirschot const MCExpr *NewRHS = tryFoldHelper(RHS, KBM, Ctx); 643bfce1aaeSJanek van Oirschot if (NewLHS != LHS || NewRHS != RHS) 644bfce1aaeSJanek van Oirschot return MCBinaryExpr::create(BExpr->getOpcode(), NewLHS, NewRHS, Ctx, 645bfce1aaeSJanek van Oirschot BExpr->getLoc()); 646bfce1aaeSJanek van Oirschot return Expr; 647bfce1aaeSJanek van Oirschot } 648bfce1aaeSJanek van Oirschot case MCExpr::ExprKind::Unary: { 649bfce1aaeSJanek van Oirschot const MCUnaryExpr *UExpr = cast<MCUnaryExpr>(Expr); 650bfce1aaeSJanek van Oirschot const MCExpr *SubExpr = UExpr->getSubExpr(); 651bfce1aaeSJanek van Oirschot const MCExpr *NewSubExpr = tryFoldHelper(SubExpr, KBM, Ctx); 652bfce1aaeSJanek van Oirschot if (SubExpr != NewSubExpr) 653bfce1aaeSJanek van Oirschot return MCUnaryExpr::create(UExpr->getOpcode(), NewSubExpr, Ctx, 654bfce1aaeSJanek van Oirschot UExpr->getLoc()); 655bfce1aaeSJanek van Oirschot return Expr; 656bfce1aaeSJanek van Oirschot } 657bfce1aaeSJanek van Oirschot case MCExpr::ExprKind::Target: { 658bfce1aaeSJanek van Oirschot const AMDGPUMCExpr *AGVK = cast<AMDGPUMCExpr>(Expr); 659bfce1aaeSJanek van Oirschot SmallVector<const MCExpr *, 8> NewArgs; 660bfce1aaeSJanek van Oirschot bool Changed = false; 661bfce1aaeSJanek van Oirschot for (const MCExpr *Arg : AGVK->getArgs()) { 662bfce1aaeSJanek van Oirschot const MCExpr *NewArg = tryFoldHelper(Arg, KBM, Ctx); 663bfce1aaeSJanek van Oirschot NewArgs.push_back(NewArg); 664bfce1aaeSJanek van Oirschot Changed |= Arg != NewArg; 665bfce1aaeSJanek van Oirschot } 666bfce1aaeSJanek van Oirschot return Changed ? AMDGPUMCExpr::create(AGVK->getKind(), NewArgs, Ctx) : Expr; 667bfce1aaeSJanek van Oirschot } 668bfce1aaeSJanek van Oirschot } 669bfce1aaeSJanek van Oirschot return Expr; 670bfce1aaeSJanek van Oirschot } 671bfce1aaeSJanek van Oirschot 672bfce1aaeSJanek van Oirschot const MCExpr *llvm::AMDGPU::foldAMDGPUMCExpr(const MCExpr *Expr, 673bfce1aaeSJanek van Oirschot MCContext &Ctx) { 674bfce1aaeSJanek van Oirschot KnownBitsMap KBM; 675bfce1aaeSJanek van Oirschot knownBitsMapHelper(Expr, KBM); 676bfce1aaeSJanek van Oirschot const MCExpr *NewExpr = tryFoldHelper(Expr, KBM, Ctx); 677bfce1aaeSJanek van Oirschot 678bfce1aaeSJanek van Oirschot return Expr != NewExpr ? NewExpr : Expr; 679bfce1aaeSJanek van Oirschot } 680bfce1aaeSJanek van Oirschot 681bfce1aaeSJanek van Oirschot void llvm::AMDGPU::printAMDGPUMCExpr(const MCExpr *Expr, raw_ostream &OS, 682bfce1aaeSJanek van Oirschot const MCAsmInfo *MAI) { 683bfce1aaeSJanek van Oirschot int64_t Val; 684bfce1aaeSJanek van Oirschot if (Expr->evaluateAsAbsolute(Val)) { 685bfce1aaeSJanek van Oirschot OS << Val; 686bfce1aaeSJanek van Oirschot return; 687bfce1aaeSJanek van Oirschot } 688bfce1aaeSJanek van Oirschot 689bfce1aaeSJanek van Oirschot Expr->print(OS, MAI); 690bfce1aaeSJanek van Oirschot } 691