[mlir] Cleanup lingering problems surrounding attribute/type aliases

This commit refactors attribute/type alias generation to be similar to how
we do it for operations, i.e. we generate aliases determined on what is
actually necessary when printing the IR (using a dummy printer for alias
collection). This allows for generating aliases only when necessary, and
also allows for proper propagation of when a nested alias can be deferred.
This also necessitated a fix for location parsing to actually parse aliases
instead of ignoring them.

Fixes #59041

Differential Revision: https://reviews.llvm.org/D138886
This commit is contained in:
River Riddle 2022-11-28 18:35:00 -08:00
parent 658a503937
commit aef89c8b41
9 changed files with 273 additions and 86 deletions

View File

@ -181,7 +181,7 @@ public:
virtual void printSymbolName(StringRef symbolRef);
/// Print a handle to the given dialect resource.
void printResourceHandle(const AsmDialectResourceHandle &resource);
virtual void printResourceHandle(const AsmDialectResourceHandle &resource);
/// Print an optional arrow followed by a type list.
template <typename TypeRange>

View File

@ -149,6 +149,16 @@ ParseResult Parser::parseNameOrFileLineColLocation(LocationAttr &loc) {
}
ParseResult Parser::parseLocationInstance(LocationAttr &loc) {
// Handle aliases.
if (getToken().is(Token::hash_identifier)) {
Attribute locAttr = parseExtendedAttr(Type());
if (!locAttr)
return failure();
if (!(loc = dyn_cast<LocationAttr>(locAttr)))
return emitError("expected location attribute, but got") << locAttr;
return success();
}
// Handle either name or filelinecol locations.
if (getToken().is(Token::string))
return parseNameOrFileLineColLocation(loc);

View File

@ -389,7 +389,8 @@ protected:
bool withKeyword = false);
void printNamedAttribute(NamedAttribute attr);
void printTrailingLocation(Location loc, bool allowAlias = true);
void printLocationInternal(LocationAttr loc, bool pretty = false);
void printLocationInternal(LocationAttr loc, bool pretty = false,
bool isTopLevel = false);
/// Print a dense elements attribute. If 'allowHex' is true, a hex string is
/// used instead of individual elements when the elements attr is large.
@ -495,14 +496,21 @@ public:
/// Visit the given attribute to see if it has an alias. `canBeDeferred` is
/// set to true if the originator of this attribute can resolve the alias
/// after parsing has completed (e.g. in the case of operation locations).
/// Returns the maximum alias depth of the attribute.
size_t visit(Attribute attr, bool canBeDeferred = false) {
return visitImpl(attr, aliases, canBeDeferred);
/// `elideType` indicates if the type of the attribute should be skipped when
/// looking for nested aliases. Returns the maximum alias depth of the
/// attribute, and the alias index of this attribute.
std::pair<size_t, size_t> visit(Attribute attr, bool canBeDeferred = false,
bool elideType = false) {
return visitImpl(attr, aliases, canBeDeferred, elideType);
}
/// Visit the given type to see if it has an alias. Returns the maximum alias
/// depth of the type.
size_t visit(Type type) { return visitImpl(type, aliases); }
/// Visit the given type to see if it has an alias. `canBeDeferred` is
/// set to true if the originator of this attribute can resolve the alias
/// after parsing has completed. Returns the maximum alias depth of the type,
/// and the alias index of this type.
std::pair<size_t, size_t> visit(Type type, bool canBeDeferred = false) {
return visitImpl(type, aliases, canBeDeferred);
}
private:
struct InProgressAliasInfo {
@ -530,16 +538,23 @@ private:
bool isType : 1;
/// If this alias can be deferred or not.
bool canBeDeferred : 1;
/// Indices for child aliases.
SmallVector<size_t> childIndices;
};
/// Visit the given attribute or type to see if it has an alias.
/// `canBeDeferred` is set to true if the originator of this value can resolve
/// the alias after parsing has completed (e.g. in the case of operation
/// locations). Returns the maximum alias depth of the value.
template <typename T>
size_t visitImpl(T value,
llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
bool canBeDeferred = false);
/// locations). Returns the maximum alias depth of the value, and its alias
/// index.
template <typename T, typename... PrintArgs>
std::pair<size_t, size_t>
visitImpl(T value,
llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
bool canBeDeferred, PrintArgs &&...printArgs);
/// Mark the given alias as non-deferrable.
void markAliasNonDeferrable(size_t aliasIndex);
/// Try to generate an alias for the provided symbol. If an alias is
/// generated, the provided alias mapping and reverse mapping are updated.
@ -722,7 +737,7 @@ private:
/// The following are hooks of `OpAsmPrinter` that are not necessary for
/// determining potential aliases.
void printFloat(const APFloat &value) override {}
void printFloat(const APFloat &) override {}
void printAffineMapOfSSAIds(AffineMapAttr, ValueRange) override {}
void printAffineExprOfSSAIds(AffineExpr, ValueRange, ValueRange) override {}
void printNewline() override {}
@ -736,6 +751,7 @@ private:
os << "%";
}
void printKeywordOrString(StringRef) override {}
void printResourceHandle(const AsmDialectResourceHandle &) override {}
void printSymbolName(StringRef) override {}
void printSuccessor(Block *) override {}
void printSuccessorAndUseList(Block *, ValueRange) override {}
@ -750,6 +766,149 @@ private:
/// A dummy output stream.
mutable llvm::raw_null_ostream os;
};
class DummyAliasDialectAsmPrinter : public DialectAsmPrinter {
public:
explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
bool canBeDeferred,
SmallVectorImpl<size_t> &childIndices)
: initializer(initializer), canBeDeferred(canBeDeferred),
childIndices(childIndices) {}
/// Print the given attribute/type, visiting any nested aliases that would be
/// generated as part of printing. Returns the maximum alias depth found while
/// printing the given value.
template <typename T, typename... PrintArgs>
size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
printAndVisitNestedAliasesImpl(value, printArgs...);
return maxAliasDepth;
}
private:
/// Print the given attribute/type, visiting any nested aliases that would be
/// generated as part of printing.
void printAndVisitNestedAliasesImpl(Attribute attr, bool elideType) {
if (!isa<BuiltinDialect>(attr.getDialect()))
return attr.getDialect().printAttribute(attr, *this);
// Process the builtin attributes.
if (attr.isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
IntegerSetAttr, UnitAttr>())
return;
if (auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
for (const NamedAttribute &nestedAttr : dictAttr.getValue()) {
printAttribute(nestedAttr.getName());
printAttribute(nestedAttr.getValue());
}
} else if (auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
for (Attribute nestedAttr : arrayAttr.getValue())
printAttribute(nestedAttr);
} else if (auto typeAttr = dyn_cast<TypeAttr>(attr)) {
printType(typeAttr.getValue());
} else if (auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
printAttribute(locAttr.getFallbackLocation());
} else if (auto locAttr = dyn_cast<NameLoc>(attr)) {
if (!isa<UnknownLoc>(locAttr.getChildLoc()))
printAttribute(locAttr.getChildLoc());
} else if (auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
printAttribute(locAttr.getCallee());
printAttribute(locAttr.getCaller());
} else if (auto locAttr = dyn_cast<FusedLoc>(attr)) {
if (Attribute metadata = locAttr.getMetadata())
printAttribute(metadata);
for (Location nestedLoc : locAttr.getLocations())
printAttribute(nestedLoc);
}
// Don't print the type if we must elide it, or if it is a None type.
if (!elideType) {
if (auto typedAttr = attr.dyn_cast<TypedAttr>()) {
Type attrType = typedAttr.getType();
if (!attrType.isa<NoneType>())
printType(attrType);
}
}
}
void printAndVisitNestedAliasesImpl(Type type) {
if (!isa<BuiltinDialect>(type.getDialect()))
return type.getDialect().printType(type, *this);
// Only visit the layout of memref if it isn't the identity.
if (auto memrefTy = type.dyn_cast<MemRefType>()) {
printType(memrefTy.getElementType());
MemRefLayoutAttrInterface layout = memrefTy.getLayout();
if (!layout.isa<AffineMapAttr>() || !layout.isIdentity())
printAttribute(memrefTy.getLayout());
if (memrefTy.getMemorySpace())
printAttribute(memrefTy.getMemorySpace());
return;
}
// For most builtin types, we can simply walk the sub elements.
if (auto subElementInterface = dyn_cast<SubElementTypeInterface>(type)) {
auto visitFn = [&](auto element) {
if (element)
(void)printAlias(element);
};
subElementInterface.walkImmediateSubElements(visitFn, visitFn);
}
}
/// Consider the given type to be printed for an alias.
void printType(Type type) override {
recordAliasResult(initializer.visit(type, canBeDeferred));
}
/// Consider the given attribute to be printed for an alias.
void printAttribute(Attribute attr) override {
recordAliasResult(initializer.visit(attr, canBeDeferred));
}
void printAttributeWithoutType(Attribute attr) override {
recordAliasResult(
initializer.visit(attr, canBeDeferred, /*elideType=*/true));
}
LogicalResult printAlias(Attribute attr) override {
printAttribute(attr);
return success();
}
LogicalResult printAlias(Type type) override {
printType(type);
return success();
}
/// Record the alias result of a child element.
void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
childIndices.push_back(aliasDepthAndIndex.second);
if (aliasDepthAndIndex.first > maxAliasDepth)
maxAliasDepth = aliasDepthAndIndex.first;
}
/// Return a null stream as the output stream, this will ignore any data fed
/// to it.
raw_ostream &getStream() const override { return os; }
/// The following are hooks of `DialectAsmPrinter` that are not necessary for
/// determining potential aliases.
void printFloat(const APFloat &) override {}
void printKeywordOrString(StringRef) override {}
void printSymbolName(StringRef) override {}
void printResourceHandle(const AsmDialectResourceHandle &) override {}
/// The initializer to use when identifying aliases.
AliasInitializer &initializer;
/// If the aliases visited by this printer can be deferred.
bool canBeDeferred;
/// The indices of child aliases.
SmallVectorImpl<size_t> &childIndices;
/// The maximum alias depth found by the printer.
size_t maxAliasDepth = 0;
/// A dummy output stream.
mutable llvm::raw_null_ostream os;
};
} // namespace
/// Sanitize the given name such that it can be used as a valid identifier. If
@ -836,48 +995,48 @@ void AliasInitializer::initialize(
initializeAliases(aliases, attrTypeToAlias);
}
template <typename T>
size_t AliasInitializer::visitImpl(
template <typename T, typename... PrintArgs>
std::pair<size_t, size_t> AliasInitializer::visitImpl(
T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
bool canBeDeferred) {
bool canBeDeferred, PrintArgs &&...printArgs) {
auto [it, inserted] =
aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
size_t aliasIndex = std::distance(aliases.begin(), it);
if (!inserted) {
// Make sure that the alias isn't deferred if we don't permit it.
if (!canBeDeferred)
it->second.canBeDeferred = false;
return it->second.aliasDepth;
markAliasNonDeferrable(aliasIndex);
return {static_cast<size_t>(it->second.aliasDepth), aliasIndex};
}
// Try to generate an alias for this attribute.
// Try to generate an alias for this value.
generateAlias(value, it->second, canBeDeferred);
size_t aliasIndex = std::distance(aliases.begin(), it);
// Check for any sub elements.
using SubElementInterfaceT =
std::conditional_t<std::is_same_v<T, Type>, SubElementTypeInterface,
SubElementAttrInterface>;
if (auto subElementInterface = dyn_cast<SubElementInterfaceT>(value)) {
size_t maxAliasDepth = 0;
auto visitSubElement = [&](auto element) {
if (!element)
return;
if (size_t depth = visit(element))
maxAliasDepth = std::max(maxAliasDepth, depth + 1);
};
subElementInterface.walkImmediateSubElements(visitSubElement,
visitSubElement);
// Print the value, capturing any nested elements that require aliases.
SmallVector<size_t> childAliases;
DummyAliasDialectAsmPrinter printer(*this, canBeDeferred, childAliases);
size_t maxAliasDepth =
printer.printAndVisitNestedAliases(value, printArgs...);
// Make sure to recompute `it` in case the map was reallocated.
it = std::next(aliases.begin(), aliasIndex);
// Make sure to recompute `it` in case the map was reallocated.
it = std::next(aliases.begin(), aliasIndex);
// If we had sub elements, update to account for the depth.
if (maxAliasDepth)
it->second.aliasDepth = maxAliasDepth;
}
// If we had sub elements, update to account for the depth.
it->second.childIndices = std::move(childAliases);
if (maxAliasDepth)
it->second.aliasDepth = maxAliasDepth + 1;
// Propagate the alias depth of the value.
return it->second.aliasDepth;
return {(size_t)it->second.aliasDepth, aliasIndex};
}
void AliasInitializer::markAliasNonDeferrable(size_t aliasIndex) {
auto it = std::next(aliases.begin(), aliasIndex);
it->second.canBeDeferred = false;
// Propagate the non-deferrable flag to any child aliases.
for (size_t childIndex : it->second.childIndices)
markAliasNonDeferrable(childIndex);
}
template <typename T>
@ -1681,7 +1840,12 @@ void AsmPrinter::Impl::printTrailingLocation(Location loc, bool allowAlias) {
printLocation(loc, /*allowAlias=*/allowAlias);
}
void AsmPrinter::Impl::printLocationInternal(LocationAttr loc, bool pretty) {
void AsmPrinter::Impl::printLocationInternal(LocationAttr loc, bool pretty,
bool isTopLevel) {
// If this isn't a top-level location, check for an alias.
if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
return;
TypeSwitch<LocationAttr>(loc)
.Case<OpaqueLoc>([&](OpaqueLoc loc) {
printLocationInternal(loc.getFallbackLocation(), pretty);
@ -1802,11 +1966,11 @@ static void printFloatValue(const APFloat &apValue, raw_ostream &os) {
void AsmPrinter::Impl::printLocation(LocationAttr loc, bool allowAlias) {
if (printerFlags.shouldPrintDebugInfoPrettyForm())
return printLocationInternal(loc, /*pretty=*/true);
return printLocationInternal(loc, /*pretty=*/true, /*isTopLevel=*/true);
os << "loc(";
if (!allowAlias || failed(printAlias(loc)))
printLocationInternal(loc);
printLocationInternal(loc, /*pretty=*/false, /*isTopLevel=*/true);
os << ')';
}

View File

@ -2,10 +2,12 @@
// Round-tripping the syntax.
// CHECK: #[[MAP:.*]] = affine_map<(d0) -> (d0)>
"test.unknown_op"() {
// CHECK: #dlti.dl_entry<"test.identifier", 42 : i64>
test.unknown_attr_1 = #dlti.dl_entry<"test.identifier", 42 : i64>,
// CHECK: #dlti.dl_entry<"test.identifier", affine_map<(d0) -> (d0)>>
// CHECK: #dlti.dl_entry<"test.identifier", #[[MAP]]>
test.unknown_attr_2 = #dlti.dl_entry<"test.identifier", affine_map<(d0) -> (d0)>>,
// CHECK: #dlti.dl_entry<i32, 32 : index>
test.unknown_attr_3 = #dlti.dl_entry<i32, 32 : index>,

View File

@ -84,7 +84,7 @@
// CHECK: } attributes {"Emitted from" = "linalg.generic"}
// CHECK: %[[VAL_59:.*]] = vector.insertelement %[[VAL_60:.*]]#2, %[[VAL_4]]{{\[}}%[[VAL_6]] : index] : vector<8xf64>
// CHECK: %[[VAL_61:.*]] = scf.for %[[VAL_62:.*]] = %[[VAL_60]]#0 to %[[VAL_21]] step %[[VAL_3]] iter_args(%[[VAL_63:.*]] = %[[VAL_59]]) -> (vector<8xf64>) {
// CHECK: %[[VAL_64:.*]] = affine.min #map2(%[[VAL_21]], %[[VAL_62]]){{\[}}%[[VAL_3]]]
// CHECK: %[[VAL_64:.*]] = affine.min #map(%[[VAL_21]], %[[VAL_62]]){{\[}}%[[VAL_3]]]
// CHECK: %[[VAL_65:.*]] = vector.create_mask %[[VAL_64]] : vector<8xi1>
// CHECK: %[[VAL_66:.*]] = vector.maskedload %[[VAL_10]]{{\[}}%[[VAL_62]]], %[[VAL_65]], %[[VAL_4]] : memref<?xf64>, vector<8xi1>, vector<8xf64> into vector<8xf64>
// CHECK: %[[VAL_67:.*]] = arith.addf %[[VAL_63]], %[[VAL_66]] : vector<8xf64>
@ -92,7 +92,7 @@
// CHECK: scf.yield %[[VAL_68]] : vector<8xf64>
// CHECK: } {"Emitted from" = "linalg.generic"}
// CHECK: %[[VAL_69:.*]] = scf.for %[[VAL_70:.*]] = %[[VAL_60]]#1 to %[[VAL_23]] step %[[VAL_3]] iter_args(%[[VAL_71:.*]] = %[[VAL_61]]) -> (vector<8xf64>) {
// CHECK: %[[VAL_73:.*]] = affine.min #map2(%[[VAL_23]], %[[VAL_70]]){{\[}}%[[VAL_3]]]
// CHECK: %[[VAL_73:.*]] = affine.min #map(%[[VAL_23]], %[[VAL_70]]){{\[}}%[[VAL_3]]]
// CHECK: %[[VAL_74:.*]] = vector.create_mask %[[VAL_73]] : vector<8xi1>
// CHECK: %[[VAL_75:.*]] = vector.maskedload %[[VAL_13]]{{\[}}%[[VAL_70]]], %[[VAL_74]], %[[VAL_4]] : memref<?xf64>, vector<8xi1>, vector<8xf64> into vector<8xf64>
// CHECK: %[[VAL_76:.*]] = arith.addf %[[VAL_71]], %[[VAL_75]] : vector<8xf64>

View File

@ -33,7 +33,7 @@
// CHECK: %[[VAL_12:.*]] = memref.load %[[VAL_8]]{{\[}}%[[VAL_5]]] : memref<?xindex>
// CHECK: %[[VAL_13:.*]] = memref.load %[[VAL_8]]{{\[}}%[[VAL_6]]] : memref<?xindex>
// CHECK: scf.for %[[VAL_14:.*]] = %[[VAL_12]] to %[[VAL_13]] step %[[VAL_1]] {
// CHECK: %[[VAL_15:.*]] = affine.min #map1(%[[VAL_13]], %[[VAL_14]]){{\[}}%[[VAL_1]]]
// CHECK: %[[VAL_15:.*]] = affine.min #map(%[[VAL_13]], %[[VAL_14]]){{\[}}%[[VAL_1]]]
// CHECK: %[[VAL_16:.*]] = vector.create_mask %[[VAL_15]] : vector<8xi1>
// CHECK: %[[VAL_17:.*]] = vector.maskedload %[[VAL_9]]{{\[}}%[[VAL_14]]], %[[VAL_16]], %[[VAL_3]] : memref<?xindex>, vector<8xi1>, vector<8xindex> into vector<8xindex>
// CHECK: %[[VAL_18:.*]] = vector.maskedload %[[VAL_10]]{{\[}}%[[VAL_14]]], %[[VAL_16]], %[[VAL_2]] : memref<?xi64>, vector<8xi1>, vector<8xi64> into vector<8xi64>
@ -99,7 +99,7 @@ func.func @sparse_index_1d_conj(%arga: tensor<8xi64, #SparseVector>) -> tensor<8
// CHECK: scf.yield %[[VAL_27]], %[[VAL_28]] : index, index
// CHECK: } attributes {"Emitted from" = "linalg.generic"}
// CHECK: scf.for %[[VAL_29:.*]] = %[[VAL_30:.*]]#1 to %[[VAL_1]] step %[[VAL_1]] {
// CHECK: %[[VAL_31:.*]] = affine.min #map1(%[[VAL_1]], %[[VAL_29]]){{\[}}%[[VAL_1]]]
// CHECK: %[[VAL_31:.*]] = affine.min #map(%[[VAL_1]], %[[VAL_29]]){{\[}}%[[VAL_1]]]
// CHECK: %[[VAL_32:.*]] = vector.create_mask %[[VAL_31]] : vector<8xi1>
// CHECK: %[[VAL_33:.*]] = vector.broadcast %[[VAL_29]] : index to vector<8xindex>
// CHECK: %[[VAL_34:.*]] = arith.addi %[[VAL_33]], %[[VAL_2]] : vector<8xindex>

View File

@ -1,4 +1,4 @@
// RUN: mlir-opt -allow-unregistered-dialect %s -mlir-print-debuginfo -mlir-pretty-debuginfo | FileCheck %s
// RUN: mlir-opt -allow-unregistered-dialect %s -mlir-print-debuginfo -mlir-pretty-debuginfo -mlir-print-local-scope | FileCheck %s
#set0 = affine_set<(d0) : (1 == 0)>

View File

@ -29,8 +29,9 @@
// CHECK-DAG: tensor<32x!test_ui8_>
"test.op"() : () -> tensor<32x!test.int<unsigned, 8>>
// CHECK-DAG: #loc2 = loc("nested")
// CHECK-DAG: #loc3 = loc(fused<#loc2>["test.mlir":10:8])
// CHECK-DAG: #loc = loc("nested")
// CHECK-DAG: #loc1 = loc("test.mlir":10:8)
// CHECK-DAG: #loc2 = loc(fused<#loc>[#loc1])
"test.op"() {alias_test = loc(fused<loc("nested")>["test.mlir":10:8])} : () -> ()
// -----
@ -39,3 +40,10 @@
// CHECK: !tuple = tuple<
// CHECK: #loc1 = loc(fused<!tuple
"test.op"() {alias_test = loc(fused<tuple<i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32>>["test.mlir":10:8])} : () -> ()
// -----
// Check that we don't print aliases for things that aren't printed.
// CHECK: #loc1 = loc(fused<memref<1xi32>
// CHECK-NOT: #map
"test.op"() {alias_test = loc(fused<memref<1xi32, affine_map<(d0) -> (d0)>>>["test.mlir":10:8])} : () -> ()

View File

@ -1,6 +1,5 @@
; RUN: mlir-translate -import-llvm -mlir-print-debuginfo -split-input-file %s | FileCheck %s
; CHECK: #[[$UNKNOWNLOC:.+]] = loc(unknown)
; CHECK-LABEL: @unknown(
define i32 @unknown(i32 %0) {
entry:
@ -10,28 +9,35 @@ end:
%1 = phi i32 [ %2, %next ]
ret i32 %1
next:
; CHECK: = llvm.mul %{{.+}}, %{{.+}} : i32 loc(#[[$UNKNOWNLOC:.+]])
; CHECK: = llvm.mul %{{.+}}, %{{.+}} : i32 loc(#[[UNKNOWNLOC:.+]])
%2 = mul i32 %0, %0
br label %end
}
; // -----
; CHECK: #[[UNKNOWNLOC:.+]] = loc(unknown)
; CHECK: #[[$SP:.+]] = #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "instruction_loc"
; CHECK: #[[$CALLEE:.+]] = #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "callee"
; // -----
; CHECK-LABEL: @instruction_loc
define i32 @instruction_loc(i32 %arg1) {
; CHECK llvm.add {{.*}} loc(#[[FILE_LOC:.*]])
; CHECK: llvm.add {{.*}} loc(#[[FILE_LOC:.*]])
%1 = add i32 %arg1, %arg1, !dbg !5
; CHECK llvm.mul {{.*}} loc(#[[CALLSITE_LOC:.*]])
; CHECK: llvm.mul {{.*}} loc(#[[CALLSITE_LOC:.*]])
%2 = mul i32 %1, %1, !dbg !7
ret i32 %2
}
; CHECK #[[FILE_LOC]] = loc(fused<#[[$SP]]>["debug-info.ll":1:2])
; CHECK #[[CALLSITE_LOC]] = loc(fused<#[[$CALLEE]]>[callsite("debug-info.ll":7:4 at fused<#[[$SP]]>["debug-info.ll":2:2])])
; CHECK-DAG: #[[RAW_FILE_LOC:.+]] = loc("debug-info.ll":1:2)
; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "instruction_loc"
; CHECK-DAG: #[[CALLEE:.+]] = #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "callee"
; CHECK-DAG: #[[FILE_LOC]] = loc(fused<#[[SP]]>[#[[RAW_FILE_LOC]]])
; CHECK-DAG: #[[CALLEE_LOC:.+]] = loc("debug-info.ll":7:4)
; CHECK-DAG: #[[RAW_CALLER_LOC:.+]] = loc("debug-info.ll":2:2)
; CHECK-DAG: #[[CALLER_LOC:.+]] = loc(fused<#[[SP]]>[#[[RAW_CALLER_LOC]]])
; CHECK-DAG: #[[RAW_CALLSITE_LOC:.+]] = loc(callsite(#[[CALLEE_LOC]] at #[[CALLER_LOC]]))
; CHECK-DAG: #[[CALLSITE_LOC]] = loc(fused<#[[CALLEE]]>[#[[RAW_CALLSITE_LOC]]])
!llvm.dbg.cu = !{!1}
!llvm.module.flags = !{!0}
@ -46,23 +52,22 @@ define i32 @instruction_loc(i32 %arg1) {
; // -----
; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit =
; CHECK: #[[$LB0:.+]] = #llvm.di_lexical_block<scope = #[[SP]]>
; CHECK: #[[$LB1:.+]] = #llvm.di_lexical_block<scope = #[[SP]], file = #[[FILE]], line = 2, column = 2>
; CHECK-LABEL: @lexical_block
define i32 @lexical_block(i32 %arg1) {
; CHECK llvm.add {{.*}} loc(#[[LOC0:.*]])
; CHECK: llvm.add {{.*}} loc(#[[LOC0:.*]])
%1 = add i32 %arg1, %arg1, !dbg !6
; CHECK llvm.mul {{.*}} loc(#[[LOC1:.*]])
; CHECK: llvm.mul {{.*}} loc(#[[LOC1:.*]])
%2 = mul i32 %arg1, %arg1, !dbg !7
ret i32 %2
}
; CHECK #[[LOC0]] = loc(fused<#[[$LB0]]>["debug-info.ll":1:2])
; CHECK #[[LOC1]] = loc(fused<#[[$LB1]]>["debug-info.ll":1:2])
; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit =
; CHECK: #[[LB0:.+]] = #llvm.di_lexical_block<scope = #[[SP]]>
; CHECK: #[[LB1:.+]] = #llvm.di_lexical_block<scope = #[[SP]], file = #[[FILE]], line = 2, column = 2>
; CHECK: #[[LOC0]] = loc(fused<#[[LB0]]>[{{.*}}])
; CHECK: #[[LOC1]] = loc(fused<#[[LB1]]>[{{.*}}])
!llvm.dbg.cu = !{!1}
!llvm.module.flags = !{!0}
@ -77,23 +82,22 @@ define i32 @lexical_block(i32 %arg1) {
; // -----
; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit =
; CHECK: #[[$LB0:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], discriminator = 0>
; CHECK: #[[$LB1:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], file = #[[FILE]], discriminator = 0>
; CHECK-LABEL: @lexical_block_file
define i32 @lexical_block_file(i32 %arg1) {
; CHECK llvm.add {{.*}} loc(#[[LOC0:.*]])
; CHECK: llvm.add {{.*}} loc(#[[LOC0:.*]])
%1 = add i32 %arg1, %arg1, !dbg !6
; CHECK llvm.mul {{.*}} loc(#[[LOC1:.*]])
; CHECK: llvm.mul {{.*}} loc(#[[LOC1:.*]])
%2 = mul i32 %arg1, %arg1, !dbg !7
ret i32 %2
}
; CHECK #[[LOC0]] = loc(fused<#[[$LB0]]>["debug-info.ll":1:2]))
; CHECK #[[LOC1]] = loc(fused<#[[$LB1]]>["debug-info.ll":2:2]))
; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit =
; CHECK: #[[LB0:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], discriminator = 0>
; CHECK: #[[LB1:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], file = #[[FILE]], discriminator = 0>
; CHECK: #[[LOC0]] = loc(fused<#[[LB0]]>[
; CHECK: #[[LOC1]] = loc(fused<#[[LB1]]>[
!llvm.dbg.cu = !{!1}
!llvm.module.flags = !{!0}
@ -206,13 +210,12 @@ define void @subprogram() !dbg !3 {
; // -----
; CHECK: #[[$SP:.+]] = #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "func_loc", file = #{{.*}}, subprogramFlags = Definition>
; CHECK-LABEL: @func_loc
define void @func_loc() !dbg !3 {
ret void
}
; CHECK: loc(fused<#[[$SP]]>["func_loc"])
; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "func_loc", file = #{{.*}}, subprogramFlags = Definition>
; CHECK: loc(fused<#[[SP]]>[
!llvm.dbg.cu = !{!1}
!llvm.module.flags = !{!0}
@ -246,9 +249,9 @@ define void @intrinsic(i64 %0, ptr %1) {
ret void
}
; CHECK: #[[LOC0]] = loc(fused<#[[$SP]]>["debug-info.ll":1:2])
; CHECK: #[[LOC1]] = loc(fused<#[[$SP]]>["debug-info.ll":2:2])
; CHECK: #[[LOC2]] = loc(fused<#[[$SP]]>["debug-info.ll":3:2])
; CHECK: #[[LOC0]] = loc(fused<#[[$SP]]>[{{.*}}])
; CHECK: #[[LOC1]] = loc(fused<#[[$SP]]>[{{.*}}])
; CHECK: #[[LOC2]] = loc(fused<#[[$SP]]>[{{.*}}])
declare void @llvm.dbg.value(metadata, metadata, metadata)
declare void @llvm.dbg.addr(metadata, metadata, metadata)