Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions tslang/include/TypeScript/MLIRLogic/MLIRCodeLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -893,14 +893,29 @@ class MLIRCustomMethods
{
MLIRCodeLogic mcl(builder, compileOptions);

if (!isa<mlir::IndexType>(startValue.getType()))
{
startValue = castFn(location, mlir::IndexType::get(builder.getContext()), startValue, genContext, false);
}
// The lowering reads start and delete count as signed (a negative start counts from the
// end), so they go to index through a signed 64-bit integer: straight from s32 to index
// is a zero extension, and -1 arrived as 4294967295.
auto toSignedIndex = [&](mlir::Value value) -> mlir::Value {
if (isa<mlir::IndexType>(value.getType()))
{
return value;
}

if (!isa<mlir::IndexType>(deleteCountValue.getType()))
auto si64Type = mlir::IntegerType::get(builder.getContext(), 64, mlir::IntegerType::Signed);
if (value.getType() != si64Type)
{
value = castFn(location, si64Type, value, genContext, false);
}

return castFn(location, mlir::IndexType::get(builder.getContext()), value, genContext, false);
};

startValue = toSignedIndex(startValue);
deleteCountValue = toSignedIndex(deleteCountValue);
if (!startValue || !deleteCountValue)
{
deleteCountValue = castFn(location, mlir::IndexType::get(builder.getContext()), deleteCountValue, genContext, false);
return mlir::failure();
}

auto arrayElement = cast<mlir_ts::ArrayType>(thisValue.getType()).getElementType();
Expand Down Expand Up @@ -936,7 +951,20 @@ class MLIRCustomMethods
ValueOrLogicalResult mlirGenArraySplice(const mlir::Location &location, ArrayRef<mlir::Value> operands,
std::function<ValueOrLogicalResult(mlir::Location, mlir::Type, mlir::Value, const GenContext &, bool)> castFn, const GenContext &genContext)
{
return mlirGenArraySplice(location, operands.front(), operands[1], operands[2], operands.slice(3), castFn, genContext);
if (operands.size() < 2)
{
emitError(location) << "splice needs the index to start at";
return mlir::failure();
}

// a left-out delete count removes everything from start on; the lowering clamps it to
// what is there (INT32_MAX stays positive in a 32-bit index too)
auto deleteCountValue = operands.size() > 2
? operands[2]
: builder.create<mlir_ts::ConstantOp>(location, builder.getIndexType(), builder.getIndexAttr(INT32_MAX)).getResult();

return mlirGenArraySplice(location, operands.front(), operands[1], deleteCountValue,
operands.size() > 3 ? operands.slice(3) : ArrayRef<mlir::Value>(), castFn, genContext);
}

ValueOrLogicalResult mlirGenArrayView(const mlir::Location &location, mlir::Value thisValue, ArrayRef<mlir::Value> values,
Expand Down
23 changes: 22 additions & 1 deletion tslang/lib/TypeScript/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3218,9 +3218,30 @@ struct ArraySpliceOpLowering : public TsLlvmPattern<mlir_ts::ArraySpliceOp>
auto startIndexAsIndexType = spliceOp.getStart();
auto decSizeAsIndexType = spliceOp.getDeleteCount();

auto startIndexAsLLVMType = rewriter.create<mlir::index::CastUOp>(loc, llvmIndexType, startIndexAsIndexType);
mlir::Value startIndexAsLLVMType = rewriter.create<mlir::index::CastUOp>(loc, llvmIndexType, startIndexAsIndexType);
mlir::Value decSizeAsLLVMType = rewriter.create<mlir::index::CastUOp>(loc, llvmIndexType, decSizeAsIndexType);

// Start and delete count arrive signed (mlirGenArraySplice). As JavaScript has it, a
// negative start counts from the end and stops at 0, a start past the end is the end, and
// a negative delete count deletes nothing. `a.splice(-1, 1)` used to take -1 as the largest
// unsigned index and fault.
{
auto zero = clh.createIndexConstantOf(llvmIndexType, 0);
auto startIsNegative =
rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::slt, startIndexAsLLVMType, zero);
auto fromEnd = rewriter.create<LLVM::AddOp>(loc, llvmIndexType, ValueRange{startIndexAsLLVMType, countAsIndexType});
auto fromEndIsNegative = rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::slt, fromEnd, zero);
auto negativeStart = rewriter.create<LLVM::SelectOp>(loc, fromEndIsNegative, zero, fromEnd);
auto startPastEnd =
rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::sgt, startIndexAsLLVMType, countAsIndexType);
auto positiveStart = rewriter.create<LLVM::SelectOp>(loc, startPastEnd, countAsIndexType, startIndexAsLLVMType);
startIndexAsLLVMType = rewriter.create<LLVM::SelectOp>(loc, startIsNegative, negativeStart, positiveStart);

auto deleteIsNegative =
rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::slt, decSizeAsLLVMType, zero);
decSizeAsLLVMType = rewriter.create<LLVM::SelectOp>(loc, deleteIsNegative, zero, decSizeAsLLVMType);
}

auto incSizeAsLLVMType = clh.createIndexConstantOf(llvmIndexType, transformed.getItems().size());

// Give back what the removed elements were holding, before anything moves or frees them.
Expand Down
31 changes: 31 additions & 0 deletions tslang/test/tester/tests/00array_splice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,36 @@ function main() {
assert(c[1] == 99, "equal 1");
assert(c[2] == 4, "equal 2");

// a negative start counts from the end; -1 used to be the largest unsigned index, and faulted
let d: number[] = [1, 2, 3, 4];
d.splice(-1, 1);
assert(d.length == 3 && d[2] == 3, "negative start");

// a start before the beginning is 0
let e: number[] = [1, 2, 3, 4];
e.splice(-10, 1);
assert(e.length == 3 && e[0] == 2, "start before 0");

// a start past the end deletes nothing
let f: number[] = [1, 2, 3, 4];
f.splice(10, 1);
assert(f.length == 4, "start past end");

// a left-out delete count removes everything from start on; it used to read past the operands
let g: number[] = [1, 2, 3, 4];
g.splice(2);
assert(g.length == 2 && g[1] == 2, "no delete count");

// a negative delete count deletes nothing
let h: number[] = [1, 2, 3, 4];
h.splice(1, -3);
assert(h.length == 4, "negative delete count");

// a `number` start, negative
let k: number[] = [1, 2, 3, 4];
const start: number = -2;
k.splice(start, 1);
assert(k.length == 3 && k[2] == 4, "number start");

print("done.");
}
Loading