Skip to content

Commit 4b4fb1d

Browse files
authored
Merge pull request intel#254 from frasercrmck/better-cfg-convert-diags
[vecz] Provide more context when CFG conversion fails
2 parents 107bc22 + c7313ef commit 4b4fb1d

File tree

4 files changed

+102
-24
lines changed

4 files changed

+102
-24
lines changed

llvm/lib/SYCLNativeCPUUtils/compiler_passes/vecz/source/debugging.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,39 @@ namespace vecz {
2626
///
2727
/// @param[in] V The value (can be `nullptr`) to be included in the remark
2828
/// @param[in] Msg The main remark message
29+
/// @param[in] Note An optional additional note to provide more context/info.
2930
/// @return The remark message as it is to be printed
30-
static std::string createRemarkMessage(const Value *V, StringRef Msg) {
31+
static std::string createRemarkMessage(const Value *V, StringRef Msg,
32+
StringRef Note = "") {
3133
std::string helper_str("Vecz: ");
3234
raw_string_ostream helper_stream(helper_str);
3335
helper_stream << Msg;
3436
if (V) {
3537
if (isa<Instruction>(V)) {
3638
// Instructions are already prefixed by two spaces when printed
37-
V->print(helper_stream, true);
39+
V->print(helper_stream, /*IsForDebug=*/true);
3840
} else if (const Function *F = dyn_cast<Function>(V)) {
39-
// Printing a functions leads to it's whole body being printed
41+
// Printing a functions leads to its whole body being printed
4042
helper_stream << " function \"" << F->getName() << "\"";
4143
} else {
4244
helper_stream << " ";
43-
V->print(helper_stream, true);
45+
V->print(helper_stream, /*IsForDebug=*/true);
4446
}
4547
}
4648
helper_stream << '\n';
4749

50+
// Provide extra context, if supplied
51+
if (!Note.empty()) {
52+
helper_stream << " note: " << Note << '\n';
53+
}
54+
4855
return helper_stream.str();
4956
}
5057

51-
void emitVeczRemarkMissed(const Function *F, const Value *V, StringRef Msg) {
58+
void emitVeczRemarkMissed(const Function *F, const Value *V, StringRef Msg,
59+
StringRef Note) {
5260
const Instruction *I = V ? dyn_cast<Instruction>(V) : nullptr;
53-
auto RemarkMsg = createRemarkMessage(V, Msg);
61+
auto RemarkMsg = createRemarkMessage(V, Msg, Note);
5462
OptimizationRemarkEmitter ORE(F);
5563
if (I) {
5664
ORE.emit(OptimizationRemarkMissed("vecz", "vecz", I) << RemarkMsg);
@@ -61,8 +69,8 @@ void emitVeczRemarkMissed(const Function *F, const Value *V, StringRef Msg) {
6169
}
6270
}
6371

64-
void emitVeczRemarkMissed(const Function *F, StringRef Msg) {
65-
emitVeczRemarkMissed(F, nullptr, Msg);
72+
void emitVeczRemarkMissed(const Function *F, StringRef Msg, StringRef Note) {
73+
emitVeczRemarkMissed(F, nullptr, Msg, Note);
6674
}
6775

6876
void emitVeczRemark(const Function *F, const Value *V, StringRef Msg) {

llvm/lib/SYCLNativeCPUUtils/compiler_passes/vecz/source/include/debugging.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <llvm/IR/Module.h>
2929
#include <llvm/IR/PassManager.h>
3030
#include <llvm/IR/Value.h>
31+
#include <llvm/Support/Error.h>
3132
#include <llvm/Support/raw_ostream.h>
3233

3334
#include <cstdlib>
@@ -64,6 +65,12 @@ struct VeczFailResult {
6465
operator std::optional<T>() const {
6566
return std::nullopt;
6667
}
68+
69+
/// @brief For functions that return an llvm::Error
70+
operator llvm::Error() const {
71+
return llvm::make_error<llvm::StringError>("Unknown VeczFailResult",
72+
llvm::inconvertibleErrorCode());
73+
}
6774
};
6875

6976
struct AnalysisFailResult : public internal::VeczFailResult {
@@ -175,13 +182,16 @@ struct AnalysisFailResult : public internal::VeczFailResult {
175182
/// @param[in] F The function in which we are currently working
176183
/// @param[in] V The value (can be `nullptr`) to be included in the message
177184
/// @param[in] Msg The main remark message text
185+
/// @param[in] Note An optional additional note to provide more context/info.
178186
void emitVeczRemarkMissed(const llvm::Function *F, const llvm::Value *V,
179-
llvm::StringRef Msg);
187+
llvm::StringRef Msg, llvm::StringRef Note = "");
180188
/// @brief Emit a RemarkMissed message
181189
///
182190
/// @param[in] F The function in which we are currently working
183191
/// @param[in] Msg The main remark message text
184-
void emitVeczRemarkMissed(const llvm::Function *F, llvm::StringRef Msg);
192+
/// @param[in] Note An optional additional note to provide more context/info.
193+
void emitVeczRemarkMissed(const llvm::Function *F, llvm::StringRef Msg,
194+
llvm::StringRef Note = "");
185195
/// @brief Emit a Remark message
186196
///
187197
/// @param[in] F The function in which we are currently working

llvm/lib/SYCLNativeCPUUtils/compiler_passes/vecz/source/transform/control_flow_conversion_pass.cpp

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <llvm/IR/Dominators.h>
3131
#include <llvm/IR/IRBuilder.h>
3232
#include <llvm/Support/Debug.h>
33+
#include <llvm/Support/Error.h>
3334
#include <llvm/Support/raw_ostream.h>
3435

3536
#include <queue>
@@ -145,17 +146,19 @@ class ControlFlowConversionState::Impl : public ControlFlowConversionState {
145146
/// @brief Apply masks to basic blocks in the function, to prevent
146147
/// side-effects for inactive instances.
147148
///
148-
/// @return true if masks were applied successfully, false otherwise.
149-
bool applyMasks();
149+
/// @return llvm::Error::success if masks were applied successfully, an error
150+
/// message explaining the failure otherwise.
151+
Error applyMasks();
150152

151153
/// @brief Apply a mask to the given basic block, to prevent side-effects for
152154
/// inactive instances.
153155
///
154156
/// @param[in] BB Basic block to apply masks to.
155157
/// @param[in] mask Mask to apply.
156158
///
157-
/// @return true if masks were applied successfully, false otherwise.
158-
bool applyMask(BasicBlock &BB, Value *mask);
159+
/// @return llvm::Error::success if masks were applied successfully, an error
160+
/// message explaining the failure otherwise.
161+
Error applyMask(BasicBlock &BB, Value *mask);
159162

160163
/// @brief Emit a call instructions to the masked version of the called
161164
/// function.
@@ -378,6 +381,14 @@ Instruction *copyExitMask(Value *mask, StringRef base, BasicBlock &BB) {
378381
VECZ_ERROR_IF(!mask, "Trying to copy exit mask with invalid arguments");
379382
return copyMask(mask, base + ".exit_mask", BB.getTerminator());
380383
}
384+
385+
/// Wrap a string into an llvm::StringError, pointing to an instruction.
386+
static inline Error makeStringError(const Twine &message, Instruction &I) {
387+
std::string helper_str = message.str();
388+
raw_string_ostream helper_stream(helper_str);
389+
helper_stream << " " << I;
390+
return make_error<StringError>(helper_stream.str(), inconvertibleErrorCode());
391+
}
381392
} // namespace
382393

383394
////////////////////////////////////////////////////////////////////////////////
@@ -538,8 +549,9 @@ bool ControlFlowConversionState::Impl::convertToDataFlow() {
538549
"Could not generate masks for");
539550
return false;
540551
}
541-
if (!applyMasks()) {
542-
emitVeczRemarkMissed(&F, VU.scalarFunction(), "Could not apply masks for");
552+
if (auto err = applyMasks()) {
553+
emitVeczRemarkMissed(&F, VU.scalarFunction(), "Could not apply masks for",
554+
llvm::toString(std::move(err)));
543555
return false;
544556
}
545557

@@ -1075,19 +1087,21 @@ bool ControlFlowConversionState::Impl::createCombinedLoopExitMask(
10751087
return true;
10761088
}
10771089

1078-
bool ControlFlowConversionState::Impl::applyMasks() {
1090+
Error ControlFlowConversionState::Impl::applyMasks() {
10791091
for (auto &BB : F) {
10801092
// Use masks with instructions that have side-effects.
10811093
if (!DR->isUniform(BB) && !DR->isByAll(BB)) {
10821094
auto *const entryMask = MaskInfos[&BB].entryMask;
10831095
VECZ_ERROR_IF(!entryMask, "BasicBlock should have an entry mask");
1084-
VECZ_FAIL_IF(!applyMask(BB, entryMask));
1096+
if (auto err = applyMask(BB, entryMask)) {
1097+
return err;
1098+
}
10851099
}
10861100
}
1087-
return true;
1101+
return Error::success();
10881102
}
10891103

1090-
bool ControlFlowConversionState::Impl::applyMask(BasicBlock &BB, Value *mask) {
1104+
Error ControlFlowConversionState::Impl::applyMask(BasicBlock &BB, Value *mask) {
10911105
// Packetization hasn't happened yet so this better be a scalar 1 bit int.
10921106
assert(mask->getType()->isIntegerTy(1) && "CFG mask type should be int1");
10931107
// Map the unmasked instruction with the masked one.
@@ -1102,17 +1116,17 @@ bool ControlFlowConversionState::Impl::applyMask(BasicBlock &BB, Value *mask) {
11021116
// Turn loads and stores into masked loads and stores.
11031117
if (memOp && (memOp->isLoad() || memOp->isStore())) {
11041118
if (!tryApplyMaskToMemOp(*memOp, mask, toDelete)) {
1105-
return false;
1119+
return makeStringError("Could not apply mask to MemOp", I);
11061120
}
11071121
} else if (auto *CI = dyn_cast<CallInst>(&I)) {
11081122
// Turn calls into masked calls if possible.
11091123
if (!applyMaskToCall(CI, mask, toDelete)) {
1110-
return false;
1124+
return makeStringError("Could not apply mask to call instruction", I);
11111125
}
11121126
} else if (I.isAtomic() && !isa<FenceInst>(&I)) {
11131127
// We need to apply masks to atomic functions, but it is currently not
11141128
// implemented. See CA-3294.
1115-
return false;
1129+
return makeStringError("Could not apply mask to atomic instruction", I);
11161130
} else if (auto *branch = dyn_cast<BranchInst>(&I)) {
11171131
// We have to be careful with infinite loops, because if they exist on a
11181132
// divergent code path, they will always be entered and will hang the
@@ -1138,7 +1152,8 @@ bool ControlFlowConversionState::Impl::applyMask(BasicBlock &BB, Value *mask) {
11381152
updateMaps(unmasked, masked);
11391153
IRCleanup::deleteInstructionNow(unmasked);
11401154
}
1141-
return true;
1155+
1156+
return Error::success();
11421157
}
11431158

11441159
CallInst *ControlFlowConversionState::Impl::emitMaskedVersion(CallInst *CI,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
; Copyright (C) Codeplay Software Limited
2+
;
3+
; Licensed under the Apache License, Version 2.0 (the "License") with LLVM
4+
; Exceptions; you may not use this file except in compliance with the License.
5+
; You may obtain a copy of the License at
6+
;
7+
; https://github.com/codeplaysoftware/oneapi-construction-kit/blob/main/LICENSE.txt
8+
;
9+
; Unless required by applicable law or agreed to in writing, software
10+
; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
; License for the specific language governing permissions and limitations
13+
; under the License.
14+
;
15+
; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
16+
17+
; RUN: veczc -w 4 -vecz-passes=cfg-convert,verify -S \
18+
; RUN: --pass-remarks-missed=vecz < %s 2>&1 | FileCheck %s
19+
20+
target triple = "spir64-unknown-unknown"
21+
target datalayout = "e-p:64:64:64-m:e-i64:64-f80:128-n8:16:32:64-S128"
22+
23+
; CHECK: Vecz: Could not apply masks for function "kernel"
24+
; CHECK-NEXT: note: Could not apply mask to atomic instruction
25+
; CHECK-SAME: %atomic = atomicrmw add ptr %arrayidx.in, i32 2 monotonic, align 4
26+
27+
define spir_kernel void @kernel(ptr %in, ptr %out) {
28+
entry:
29+
%gid = tail call i64 @__mux_get_global_id(i32 0)
30+
%cmp = icmp eq i64 %gid, 0
31+
br i1 %cmp, label %if.then, label %end
32+
33+
if.then:
34+
%arrayidx.in = getelementptr inbounds i32, ptr %in, i64 %gid
35+
%atomic = atomicrmw add ptr %arrayidx.in, i32 2 monotonic, align 4
36+
br label %end
37+
38+
end:
39+
%merge = phi i32 [ 0, %entry ], [ %atomic, %if.then ]
40+
%arrayidx.out = getelementptr inbounds i32, ptr %out, i64 %gid
41+
store i32 %merge, ptr %arrayidx.out, align 4
42+
ret void
43+
}
44+
45+
declare i64 @__mux_get_global_id(i32)

0 commit comments

Comments
 (0)