Skip to content

Commit d9b1c26

Browse files
abadamsclaude
andauthored
Work around an LLVM bug in widening casts of loads in wasm (#8981)
* Work around an LLVM bug in widening casts of loads in wasm Fixes #8928 Pulls in the optimization_fence helper from #8925 Co-authored-by: Claude Code <noreply@anthropic.com> * Tweak comment * Add reference to llvm bug --------- Co-authored-by: Claude Code <noreply@anthropic.com>
1 parent 04b0eea commit d9b1c26

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

src/CodeGen_LLVM.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4937,6 +4937,27 @@ Value *CodeGen_LLVM::slice_vector(Value *vec, int start, int size) {
49374937
}
49384938
}
49394939

4940+
Value *CodeGen_LLVM::optimization_fence(Value *v) {
4941+
llvm::Type *t = v->getType();
4942+
internal_assert(!t->isScalableTy())
4943+
<< "optimization_fence does not support scalable vectors yet";
4944+
const int bits = t->getPrimitiveSizeInBits();
4945+
if (bits % 32) {
4946+
const int lanes = get_vector_num_elements(t);
4947+
const int element_bits = t->getScalarSizeInBits();
4948+
const int lanes_per_32_bits = 32 / element_bits;
4949+
const int padded_lanes = align_up(lanes, lanes_per_32_bits);
4950+
v = slice_vector(v, 0, padded_lanes);
4951+
v = optimization_fence(v);
4952+
v = slice_vector(v, 0, lanes);
4953+
return v;
4954+
}
4955+
llvm::Type *float_type = llvm_type_of(Float(32, bits / 32));
4956+
v = builder->CreateBitCast(v, float_type);
4957+
v = builder->CreateArithmeticFence(v, float_type);
4958+
return builder->CreateBitCast(v, t);
4959+
}
4960+
49404961
Value *CodeGen_LLVM::concat_vectors(const vector<Value *> &v) {
49414962
if (v.size() == 1) {
49424963
return v[0];

src/CodeGen_LLVM.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,11 @@ class CodeGen_LLVM : public IRVisitor {
509509
* if you ask for more lanes than the vector has. */
510510
virtual llvm::Value *slice_vector(llvm::Value *vec, int start, int extent);
511511

512+
/** Use an arithmetic fence to prevent LLVM from fusing operations
513+
* across this barrier. Works by bitcasting to float, applying
514+
* llvm.arithmetic.fence, and bitcasting back. */
515+
virtual llvm::Value *optimization_fence(llvm::Value *);
516+
512517
/** Concatenate a bunch of llvm vectors. Must be of the same type. */
513518
virtual llvm::Value *concat_vectors(const std::vector<llvm::Value *> &);
514519

src/CodeGen_WebAssembly.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,33 @@ void CodeGen_WebAssembly::visit(const Cast *op) {
177177
codegen(equiv);
178178
return;
179179
}
180+
181+
// Work around an LLVM bug where
182+
// WebAssemblyTargetLowering::isVectorLoadExtDesirable assumes the
183+
// operand of a vector extend is always a load, but LLVM's optimizer may
184+
// insert a freeze node between the load and the extend, causing a
185+
// cast<LoadSDNode> assertion failure. Use an optimization fence to
186+
// prevent the DAG combiner from seeing through to the load. See
187+
// https://github.com/halide/Halide/issues/8928 and
188+
// https://github.com/llvm/llvm-project/issues/184676
189+
if (op->type.is_int_or_uint() &&
190+
op->value.type().is_int_or_uint() &&
191+
op->type.bits() > op->value.type().bits()) {
192+
// Check if the value is a Load. Loads are sometimes hiding behind
193+
// let bindings.
194+
bool is_load = op->value.as<Load>();
195+
if (const Variable *var = op->value.as<Variable>()) {
196+
llvm::Value *v = sym_get(var->name, false);
197+
is_load = v && llvm::isa<llvm::LoadInst>(v);
198+
}
199+
if (is_load) {
200+
llvm::Value *v = codegen(op->value);
201+
v = optimization_fence(v);
202+
value = builder->CreateIntCast(v, llvm_type_of(op->type),
203+
op->value.type().is_int());
204+
return;
205+
}
206+
}
180207
}
181208

182209
CodeGen_Posix::visit(op);

0 commit comments

Comments
 (0)