diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h index e6a0eae9da30c..73975869d5fe4 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -203,6 +203,8 @@ enum Kind { kw_readwrite, kw_argmem, kw_inaccessiblemem, + kw_target_mem0, + kw_target_mem1, kw_errnomem, // Legacy attributes: diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 585371a6a4423..2d6a6148d4f72 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -49,6 +49,16 @@ def IntrArgMemOnly : IntrinsicProperty; // accessible by the module being compiled. This is a weaker form of IntrNoMem. def IntrInaccessibleMemOnly : IntrinsicProperty; + + +class IntrinsicMemoryLocation; +// This should be added in the Target, but once in IntrinsicsAArch64.td +def TargetMem0 : IntrinsicMemoryLocation; +def TargetMem1 : IntrinsicMemoryLocation; +// IntrInaccessible{Read|Write}MemOnly needs to set Location +class IntrInaccessibleReadMemOnly : IntrinsicProperty{IntrinsicMemoryLocation Loc=idx;} +class IntrInaccessibleWriteMemOnly : IntrinsicProperty{IntrinsicMemoryLocation Loc=idx;} + // IntrInaccessibleMemOrArgMemOnly -- This intrinsic only accesses memory that // its pointer-typed arguments point to or memory that is not accessible // by the module being compiled. This is a weaker form of IntrArgMemOnly. diff --git a/llvm/include/llvm/Support/ModRef.h b/llvm/include/llvm/Support/ModRef.h index 71f3b5bcb9c2b..9266980d635f7 100644 --- a/llvm/include/llvm/Support/ModRef.h +++ b/llvm/include/llvm/Support/ModRef.h @@ -56,6 +56,11 @@ enum class ModRefInfo : uint8_t { /// Debug print ModRefInfo. LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, ModRefInfo MR); +enum class InaccessibleTargetMemLocation { + TargetMem0 = 3, + TargetMem1 = 4, +}; + /// The locations at which a function might access memory. enum class IRMemLocation { /// Access to memory via argument pointers. @@ -65,7 +70,7 @@ enum class IRMemLocation { /// Errno memory. ErrnoMem = 2, /// Any other memory. - Other = 3, + Other = 5, /// Helpers to iterate all locations in the MemoryEffectsBase class. First = ArgMem, @@ -152,6 +157,40 @@ template class MemoryEffectsBase { return MemoryEffectsBase(Location::Other, MR); } + /// Create MemoryEffectsBase that can only read inaccessible memory. + static MemoryEffectsBase + inaccessibleReadMemOnly(Location Loc = Location::InaccessibleMem) { + return MemoryEffectsBase(Loc, ModRefInfo::Ref); + } + + /// Create MemoryEffectsBase that can only write inaccessible memory. + static MemoryEffectsBase + inaccessibleWriteMemOnly(Location Loc = Location::InaccessibleMem) { + return MemoryEffectsBase(Loc, ModRefInfo::Mod); + } + + /// Checks if only target-specific memory locations are set. + /// Ignores standard locations like ArgMem or InaccessibleMem. + /// Needed because `Data` may be non-zero by default unless explicitly + /// cleared. + bool onlyAccessTargetMemoryLocation() { + MemoryEffectsBase ME = *this; + for (unsigned I = static_cast(LocationEnum::ErrnoMem); + I < static_cast(LocationEnum::Last); I++) + ME = ME.getWithoutLoc(static_cast(I)); + return ME.doesNotAccessMemory(); + } + + /// Create MemoryEffectsBase that can only access Target Memory Locations + static MemoryEffectsBase + setTargetMemLocationModRef(ModRefInfo MR = ModRefInfo::NoModRef) { + MemoryEffectsBase FRMB = none(); + for (unsigned I = static_cast(LocationEnum::ErrnoMem); + I < static_cast(LocationEnum::Last); I++) + FRMB.setModRef(static_cast(I), MR); + return FRMB; + } + /// Create MemoryEffectsBase that can only access inaccessible or argument /// memory. static MemoryEffectsBase @@ -178,6 +217,11 @@ template class MemoryEffectsBase { return MemoryEffectsBase(Data); } + bool isTargetMemLoc(IRMemLocation Loc) { + return static_cast(Loc) > + static_cast(Location::ErrnoMem); + } + /// Convert MemoryEffectsBase into an encoded integer value (used by memory /// attribute). uint32_t toIntValue() const { @@ -232,7 +276,12 @@ template class MemoryEffectsBase { /// Whether this function only (at most) accesses inaccessible memory. bool onlyAccessesInaccessibleMem() const { - return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory(); + return getWithoutLoc(static_cast( + llvm::InaccessibleTargetMemLocation::TargetMem0)) + .getWithoutLoc(static_cast( + llvm::InaccessibleTargetMemLocation::TargetMem1)) + .getWithoutLoc(Location::InaccessibleMem) + .doesNotAccessMemory(); } /// Whether this function only (at most) accesses errno memory. diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h index d4fa1e5d65749..979507eeaa933 100644 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -25,6 +25,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ModRef.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/Timer.h" #include "llvm/Support/TrailingObjects.h" diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 3d5bd6155536e..a27377a0d6a07 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -702,6 +702,8 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(write); KEYWORD(readwrite); KEYWORD(argmem); + KEYWORD(target_mem0); + KEYWORD(target_mem1); KEYWORD(inaccessiblemem); KEYWORD(errnomem); KEYWORD(argmemonly); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 1bc2906f63b07..ce1a848d4f864 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1666,6 +1666,25 @@ static bool upgradeMemoryAttr(MemoryEffects &ME, lltok::Kind Kind) { } } +static std::optional keywordToLoc(lltok::Kind Tok) { + switch (Tok) { + case lltok::kw_argmem: + return IRMemLocation::ArgMem; + case lltok::kw_inaccessiblemem: + return IRMemLocation::InaccessibleMem; + case lltok::kw_errnomem: + return IRMemLocation::ErrnoMem; + case lltok::kw_target_mem0: + return static_cast( + llvm::InaccessibleTargetMemLocation::TargetMem0); + case lltok::kw_target_mem1: + return static_cast( + llvm::InaccessibleTargetMemLocation::TargetMem1); + default: + return std::nullopt; + } +} + /// parseFnAttributeValuePairs /// ::= | '=' bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B, @@ -2513,19 +2532,6 @@ bool LLParser::parseAllocKind(AllocFnKind &Kind) { return false; } -static std::optional keywordToLoc(lltok::Kind Tok) { - switch (Tok) { - case lltok::kw_argmem: - return IRMemLocation::ArgMem; - case lltok::kw_inaccessiblemem: - return IRMemLocation::InaccessibleMem; - case lltok::kw_errnomem: - return IRMemLocation::ErrnoMem; - default: - return std::nullopt; - } -} - static std::optional keywordToModRef(lltok::Kind Tok) { switch (Tok) { case lltok::kw_none: diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 094678f32af2b..afa0b0b7084b3 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -5011,8 +5011,8 @@ void AssemblyWriter::writeAllAttributeGroups() { asVec[I.second] = I; for (const auto &I : asVec) - Out << "attributes #" << I.second << " = { " - << I.first.getAsString(true) << " }\n"; + Out << "attributes #" << I.second << " = { " << I.first.getAsString(true) + << " }\n"; } void AssemblyWriter::printUseListOrder(const Value *V, diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index 4ac2ebd55dcac..5b4071b544ebe 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -640,6 +640,10 @@ std::string Attribute::getAsString(bool InAttrGrp) const { if (MR == OtherMR) continue; + // Dont want to print Target Location if NoModRef + if (ME.isTargetMemLoc(Loc) && (MR == ModRefInfo::NoModRef)) + continue; + if (!First) OS << ", "; First = false; @@ -656,7 +660,23 @@ std::string Attribute::getAsString(bool InAttrGrp) const { break; case IRMemLocation::Other: llvm_unreachable("This is represented as the default access kind"); + break; } + // Target Memory locations are not IRMemLocation. + // It is breaking buildbots when it treats warning as error + if (static_cast(Loc) > static_cast(IRMemLocation::ErrnoMem)) { + InaccessibleTargetMemLocation TargetMemLoc = + static_cast(Loc); + switch (TargetMemLoc) { + case InaccessibleTargetMemLocation::TargetMem0: + OS << "target_mem0: "; + break; + case InaccessibleTargetMemLocation::TargetMem1: + OS << "target_mem1: "; + break; + } + } + OS << getModRefStr(MR); } OS << ")"; diff --git a/llvm/lib/Support/ModRef.cpp b/llvm/lib/Support/ModRef.cpp index 2bb9bc945bd2e..daefae2f59dbf 100644 --- a/llvm/lib/Support/ModRef.cpp +++ b/llvm/lib/Support/ModRef.cpp @@ -49,6 +49,14 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, MemoryEffects ME) { case IRMemLocation::Other: OS << "Other: "; break; + case static_cast( + static_cast(InaccessibleTargetMemLocation::TargetMem0)): + OS << "TargetMem0: "; + break; + case static_cast( + static_cast(InaccessibleTargetMemLocation::TargetMem1)): + OS << "TargetMem1: "; + break; } OS << ME.getModRef(Loc); }); diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index 8d9a0e7eaef63..bff2ad73719ff 100644 --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -142,6 +142,9 @@ static void addLocAccess(MemoryEffects &ME, const MemoryLocation &Loc, ME |= MemoryEffects::argMemOnly(MR); ME |= MemoryEffects(IRMemLocation::ErrnoMem, MR); ME |= MemoryEffects(IRMemLocation::Other, MR); + // Should also set the other Target Memory Locations as MR. + // To compares with MemoryEffects::unknown() in addMemoryAttrs + ME |= MemoryEffects::setTargetMemLocationModRef(MR); } static void addArgLocs(MemoryEffects &ME, const CallBase *Call, diff --git a/llvm/test/Assembler/aarch64-memory-attribute.ll b/llvm/test/Assembler/aarch64-memory-attribute.ll new file mode 100644 index 0000000000000..d19b49cdac142 --- /dev/null +++ b/llvm/test/Assembler/aarch64-memory-attribute.ll @@ -0,0 +1,35 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64" + +; CHECK: Function Attrs: memory(target_mem1: write) +; CHECK: @fn_inaccessiblemem_write_target_mem1() [[ATTR0:#.*]] +declare void @fn_inaccessiblemem_write_target_mem1() + memory(target_mem1: write) + +; CHECK: Function Attrs: memory(target_mem1: read) +; CHECK: @fn_inaccessiblemem_read_target_mem1() [[ATTR1:#.*]] +declare void @fn_inaccessiblemem_read_target_mem1() + memory(target_mem1: read) + +; CHECK: Function Attrs: memory(target_mem0: write) +; CHECK: @fn_inaccessiblemem_write_target_mem0() [[ATTR2:#.*]] +declare void @fn_inaccessiblemem_write_target_mem0() + memory(target_mem0: write) + +; CHECK: ; Function Attrs: memory(target_mem0: read) +; CHECK: @fn_inaccessiblemem_read_target_mem0() [[ATTR3:#.*]] +declare void @fn_inaccessiblemem_read_target_mem0() + memory(target_mem0: read) + +; CHECK: Function Attrs: memory(target_mem0: read, target_mem1: write) +; CHECK: @fn_inaccessiblemem_read_target_mem0_write_target_mem1() [[ATTR4:#.*]] +declare void @fn_inaccessiblemem_read_target_mem0_write_target_mem1() + memory(target_mem0: read, target_mem1: write) + +; CHECK: attributes [[ATTR0]] = { memory(target_mem1: write) } +; CHECK: attributes [[ATTR1]] = { memory(target_mem1: read) } +; CHECK: attributes [[ATTR2]] = { memory(target_mem0: write) } +; CHECK: attributes [[ATTR3]] = { memory(target_mem0: read) } +; CHECK: attributes [[ATTR4]] = { memory(target_mem0: read, target_mem1: write) } diff --git a/llvm/test/Assembler/memory-attribute.ll b/llvm/test/Assembler/memory-attribute.ll index effd4ce7c4548..98eb2d88b2b52 100644 --- a/llvm/test/Assembler/memory-attribute.ll +++ b/llvm/test/Assembler/memory-attribute.ll @@ -78,3 +78,28 @@ declare void @fn_argmem_read_inaccessiblemem_write() ; CHECK: @fn_argmem_read_inaccessiblemem_write_reordered() declare void @fn_argmem_read_inaccessiblemem_write_reordered() memory(inaccessiblemem: write, argmem: read) + +; CHECK: Function Attrs: memory(target_mem1: write) +; CHECK: @fn_inaccessiblemem_write_mem_target1() +declare void @fn_inaccessiblemem_write_mem_target1() + memory(target_mem1: write) + +; CHECK: Function Attrs: memory(target_mem1: read) +; CHECK: @fn_inaccessiblemem_read_mem_target1() +declare void @fn_inaccessiblemem_read_mem_target1() + memory(target_mem1: read) + +; CHECK: Function Attrs: memory(target_mem0: write) +; CHECK: @fn_inaccessiblemem_write_target_mem0() +declare void @fn_inaccessiblemem_write_target_mem0() + memory(target_mem0: write) + +; CHECK: Function Attrs: memory(target_mem0: read) +; CHECK: @fn_inaccessiblemem_read_target_mem0() +declare void @fn_inaccessiblemem_read_target_mem0() + memory(target_mem0: read) + +; CHECK: Function Attrs: memory(target_mem0: read, target_mem1: write) +; CHECK: @fn_inaccessiblemem_read_target_mem0_write_mem_target1() +declare void @fn_inaccessiblemem_read_target_mem0_write_mem_target1() + memory(target_mem0: read, target_mem1: write) diff --git a/llvm/test/TableGen/intrinsic-attrs-fp8.td b/llvm/test/TableGen/intrinsic-attrs-fp8.td new file mode 100644 index 0000000000000..3395e56c100a8 --- /dev/null +++ b/llvm/test/TableGen/intrinsic-attrs-fp8.td @@ -0,0 +1,54 @@ +// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include -DTEST_INTRINSICS_SUPPRESS_DEFS %s | FileCheck %s + +include "llvm/IR/Intrinsics.td" + +def int_aarch64_set_fpmr_2 : DefaultAttrsIntrinsic<[], [llvm_i64_ty], [IntrInaccessibleWriteMemOnly]>; + +def int_aarch64_get_za_2 : DefaultAttrsIntrinsic<[], [llvm_i64_ty], [IntrInaccessibleReadMemOnly]>; + +def int_aarch64_get_fpmr_set_za : DefaultAttrsIntrinsic<[], [llvm_i64_ty], [IntrInaccessibleReadMemOnly, IntrInaccessibleWriteMemOnly]>; + +// CHECK: static constexpr unsigned IntrinsicNameOffsetTable[] = { +// CHECK-NEXT: 1, // not_intrinsic +// CHECK-NEXT: 15, // llvm.aarch64.get.fpmr.set.za +// CHECK-NEXT: 44, // llvm.aarch64.get.za.2 +// CHECK-NEXT: 66, // llvm.aarch64.set.fpmr.2 + +// CHECK: static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) { +// CHECK-NEXT: switch (ID) { +// CHECK-NEXT: default: llvm_unreachable("Invalid attribute set number"); +// CHECK-NEXT: case 0: +// CHECK-NEXT: return AttributeSet::get(C, { +// CHECK-NEXT: Attribute::get(C, Attribute::NoUnwind), +// CHECK-NEXT: Attribute::get(C, Attribute::NoCallback), +// CHECK-NEXT: Attribute::get(C, Attribute::NoSync), +// CHECK-NEXT: Attribute::get(C, Attribute::NoFree), +// CHECK-NEXT: Attribute::get(C, Attribute::WillReturn), +// CHECK-NEXT: // ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: NoModRef, TargetMem0: Ref, TargetMem1: Mod, Other: NoModRef +// CHECK-NEXT: Attribute::getWithMemoryEffects(C, MemoryEffects::createFromIntValue(576)), +// CHECK-NEXT: }); +// CHECK-NEXT: case 1: +// CHECK-NEXT: return AttributeSet::get(C, { +// CHECK-NEXT: Attribute::get(C, Attribute::NoUnwind), +// CHECK-NEXT: Attribute::get(C, Attribute::NoCallback), +// CHECK-NEXT: Attribute::get(C, Attribute::NoSync), +// CHECK-NEXT: Attribute::get(C, Attribute::NoFree), +// CHECK-NEXT: Attribute::get(C, Attribute::WillReturn), +// CHECK-NEXT: // ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: NoModRef, TargetMem0: NoModRef, TargetMem1: Ref, Other: NoModRef +// CHECK-NEXT: Attribute::getWithMemoryEffects(C, MemoryEffects::createFromIntValue(256)), +// CHECK-NEXT: }); +// CHECK-NEXT: case 2: +// CHECK-NEXT: return AttributeSet::get(C, { +// CHECK-NEXT: Attribute::get(C, Attribute::NoUnwind), +// CHECK-NEXT: Attribute::get(C, Attribute::NoCallback), +// CHECK-NEXT: Attribute::get(C, Attribute::NoSync), +// CHECK-NEXT: Attribute::get(C, Attribute::NoFree), +// CHECK-NEXT: Attribute::get(C, Attribute::WillReturn), +// CHECK-NEXT: // ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: NoModRef, TargetMem0: Mod, TargetMem1: NoModRef, Other: NoModRef +// CHECK-NEXT: Attribute::getWithMemoryEffects(C, MemoryEffects::createFromIntValue(128)), + +// CHECK: static constexpr uint16_t IntrinsicsToAttributesMap[] = { +// CHECK-NEXT: 0 << 1 | 0, // llvm.aarch64.get.fpmr.set.za +// CHECK-NEXT: 1 << 1 | 0, // llvm.aarch64.get.za.2 +// CHECK-NEXT: 2 << 1 | 0, // llvm.aarch64.set.fpmr.2 +// CHECK-NEXT:}; diff --git a/llvm/unittests/Support/ModRefTest.cpp b/llvm/unittests/Support/ModRefTest.cpp index 9c13908da44bb..36c926d9e2945 100644 --- a/llvm/unittests/Support/ModRefTest.cpp +++ b/llvm/unittests/Support/ModRefTest.cpp @@ -21,7 +21,8 @@ TEST(ModRefTest, PrintMemoryEffects) { raw_string_ostream OS(S); OS << MemoryEffects::none(); EXPECT_EQ(S, "ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: " - "NoModRef, Other: NoModRef"); + "NoModRef, TargetMem0: NoModRef, TargetMem1: NoModRef, Other: " + "NoModRef"); } } // namespace diff --git a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp index bc42efa3b2e9c..854866e353c34 100644 --- a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp +++ b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp @@ -374,7 +374,19 @@ void CodeGenIntrinsic::setProperty(const Record *R) { ME &= MemoryEffects::argMemOnly(); else if (R->getName() == "IntrInaccessibleMemOnly") ME &= MemoryEffects::inaccessibleMemOnly(); - else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly") + else if (R->isSubClassOf("IntrInaccessibleReadMemOnly")) { + llvm::IRMemLocation Loc = getLocationTypeAsInt(R, "Loc"); + if (ME.onlyAccessTargetMemoryLocation()) + ME = ME.getWithModRef(Loc, ModRefInfo::Ref); + else + ME &= MemoryEffects::inaccessibleReadMemOnly(Loc); + } else if (R->isSubClassOf("IntrInaccessibleWriteMemOnly")) { + llvm::IRMemLocation Loc = getLocationTypeAsInt(R, "Loc"); + if (ME.onlyAccessTargetMemoryLocation()) + ME = ME.getWithModRef(Loc, ModRefInfo::Mod); + else + ME &= MemoryEffects::inaccessibleWriteMemOnly(Loc); + } else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly") ME &= MemoryEffects::inaccessibleOrArgMemOnly(); else if (R->getName() == "Commutative") isCommutative = true; @@ -449,6 +461,23 @@ void CodeGenIntrinsic::setProperty(const Record *R) { } } +llvm::IRMemLocation +CodeGenIntrinsic::getLocationTypeAsInt(const Record *R, + StringRef FieldName) const { + const Record *LocRec = R->getValueAsDef(FieldName); + StringRef Name = LocRec->getName(); + if (Name == "TargetMem0") + return static_cast( + llvm::InaccessibleTargetMemLocation::TargetMem0); + else if (Name == "TargetMem1") + return static_cast( + llvm::InaccessibleTargetMemLocation::TargetMem1); + else if (Name == "InaccessibleMem") + return llvm::IRMemLocation::InaccessibleMem; + else + PrintFatalError(R->getLoc(), "unknown IRMemLocation: " + Name); +} + bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const { if (ParamIdx >= IS.ParamTys.size()) return false; diff --git a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.h b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.h index 676f575b2749d..875b7c02b77b8 100644 --- a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.h +++ b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.h @@ -170,6 +170,9 @@ struct CodeGenIntrinsic { bool isParamImmArg(unsigned ParamIdx) const; + llvm::IRMemLocation getLocationTypeAsInt(const Record *R, + StringRef FieldName) const; + CodeGenIntrinsic(const Record *R, const CodeGenIntrinsicContext &Ctx); };