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
21 changes: 20 additions & 1 deletion tslang/include/TypeScript/LowerToLLVM/CastLogicHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,15 @@ class CastLogicHelper
if (inType.isSignedInteger() && resType.isSignedInteger() && resType.getIntOrFloatBitWidth() > inType.getIntOrFloatBitWidth())
{
return rewriter.create<LLVM::SExtOp>(loc, resLLVMType, in);
}
}

// an unsigned integer is converted to a float as unsigned: castLLVMTypesLogic only sees the
// signless LLVM type, and its sitofp read a u32 of 0xFFFFFFFF as -1
if (inType.isUnsignedInteger() && isFloat(resLLVMType))
{
auto inValue = in.getType() == inLLVMType ? in : rewriter.create<mlir_ts::DialectCastOp>(loc, inLLVMType, in);
return rewriter.create<mlir::arith::UIToFPOp>(loc, resLLVMType, inValue);
}

auto isResAny = isa<mlir_ts::AnyType>(resType);
if (isResAny)
Expand Down Expand Up @@ -691,6 +699,17 @@ class CastLogicHelper

if (isFloat(inLLVMType) && isInt(resLLVMType))
{
// to a narrower integer through i64, then truncated: fptosi straight to i32 is poison
// outside the signed range, so a number holding a u32 above 0x7FFFFFFF (2147483649,
// say, which the unsigned int-to-float conversion now gives) came back as garbage.
// Truncating wraps modulo 2^32, as ToInt32/ToUint32 do.
auto width = resLLVMType.getIntOrFloatBitWidth();
if (width < 64)
{
auto wideValue = rewriter.create<mlir::arith::FPToSIOp>(loc, rewriter.getI64Type(), in);
return rewriter.create<LLVM::TruncOp>(loc, resLLVMType, wideValue);
}

return rewriter.create<mlir::arith::FPToSIOp>(loc, resLLVMType, in);
}

Expand Down
14 changes: 13 additions & 1 deletion tslang/include/TypeScript/LowerToLLVM/LLVMRTTIHelperVCLinux.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ class LLVMRTTIHelperVCLinux
types.push_back({linux::I32Type::typeName});
}

void setU32AsCatchType()
{
types.push_back({linux::U32Type::typeName});
}

void setBoolAsCatchType()
{
types.push_back({linux::BoolType::typeName});
Expand Down Expand Up @@ -116,7 +121,14 @@ class LLVMRTTIHelperVCLinux
.Case<mlir::IntegerType>([&](auto intType) {
if (intType.getIntOrFloatBitWidth() == 32)
{
setI32AsCatchType();
if (intType.isUnsigned())
{
setU32AsCatchType();
}
else
{
setI32AsCatchType();
}
}
else if (intType.getIntOrFloatBitWidth() == 64)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ namespace I32Type
constexpr const auto *typeName = "_ZTIi";
} // namespace I32Type

// `unsigned int` - a u32 used to be thrown as an `int`, and read back with its top bit as a sign
namespace U32Type
{
constexpr const auto *typeName = "_ZTIj";
} // namespace U32Type

namespace BoolType
{
constexpr const auto *typeName = "_ZTIb";
Expand Down
17 changes: 16 additions & 1 deletion tslang/include/TypeScript/LowerToLLVM/LLVMRTTIHelperVCWin32.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ class LLVMRTTIHelperVCWin32
throwInfoRef = I32Type::throwInfoRef;
}

void setU32AsCatchType()
{
types.push_back({U32Type::typeName, U32Type::typeInfoRef, U32Type::catchableTypeInfoRef, U32Type::catchableTypeSize});

catchableTypeInfoArrayRef = U32Type::catchableTypeInfoArrayRef;
throwInfoRef = U32Type::throwInfoRef;
}

void setBoolAsCatchType()
{
types.push_back({BoolType::typeName, BoolType::typeInfoRef, BoolType::catchableTypeInfoRef, BoolType::catchableTypeSize});
Expand Down Expand Up @@ -172,7 +180,14 @@ class LLVMRTTIHelperVCWin32
.Case<mlir::IntegerType>([&](auto intType) {
if (intType.getIntOrFloatBitWidth() == 32)
{
setI32AsCatchType();
if (intType.isUnsigned())
{
setU32AsCatchType();
}
else
{
setI32AsCatchType();
}
}
else if (intType.getIntOrFloatBitWidth() == 64)
{
Expand Down
19 changes: 19 additions & 0 deletions tslang/include/TypeScript/LowerToLLVM/LLVMRTTIHelperVCWin32Const.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,25 @@ constexpr const auto *throwInfoRef = "_TI3H";
constexpr int catchableTypeSize = 4;
} // namespace I32Type

// `unsigned int`. A u32 used to go out as an `int` (`.H`), so every reader - the `.N` widening
// thunk, the `.PEAX` box thunk - took its top bit for a sign and 0xFFFFFFFF came back as -1.
// Its records have names of their own, so they never share a thunk with an `int` throw.
namespace U32Type
{
constexpr const auto *typeName = ".I";
constexpr const auto *typeInfoRef = "??_R0I@8";
constexpr const auto *catchableTypeInfoRef = "_CT??_R0I@84";
constexpr const auto *catchableTypeInfoRef2 = "_CT??_R0PEAX@I84.box";
constexpr const auto *copyThunk2 = ".eh.copy.box.I";
constexpr const auto *typeName3 = ".N";
constexpr const auto *typeInfoRef3 = "??_R0N@8";
constexpr const auto *catchableTypeInfoRef3 = "_CT??_R0N@88.fromI";
constexpr const auto *copyThunk3 = ".eh.copy.num.I";
constexpr const auto *catchableTypeInfoArrayRef = "_CTA3I";
constexpr const auto *throwInfoRef = "_TI3I";
constexpr int catchableTypeSize = 4;
} // namespace U32Type

// `bool` - a boolean is an i1, stored as a byte
namespace BoolType
{
Expand Down
27 changes: 24 additions & 3 deletions tslang/include/TypeScript/MLIRLogic/MLIRRTTIHelperVCLinux.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ class MLIRRTTIHelperVCLinux
types.push_back({linux::I32Type::typeName, TypeInfo::Value, -1});
}

void setU32AsCatchType()
{
types.push_back({linux::U32Type::typeName, TypeInfo::Value, -1});
}

void setBoolAsCatchType()
{
types.push_back({linux::BoolType::typeName, TypeInfo::Value, -1});
Expand Down Expand Up @@ -157,7 +162,14 @@ class MLIRRTTIHelperVCLinux
auto width = intType.getIntOrFloatBitWidth();
if (width == 32)
{
setI32AsCatchType();
if (intType.isUnsigned())
{
setU32AsCatchType();
}
else
{
setI32AsCatchType();
}
}
else if (width == 64)
{
Expand Down Expand Up @@ -191,9 +203,10 @@ class MLIRRTTIHelperVCLinux
#else
setF32AsCatchType();
#endif
// a `catch (e: number)` also takes a thrown int (`throw 1`) or f32, and binding
// a `catch (e: number)` also takes a thrown int (`throw 1`), u32 or f32, and binding
// it compares against their type_infos - see TryOpLowering, SaveCatchVarOpLowering
setI32AsCatchType();
setU32AsCatchType();
setF32AsCatchType();
})
.Case<mlir_ts::BooleanType>([&](auto boolType) { setBoolAsCatchType(); })
Expand All @@ -216,6 +229,7 @@ class MLIRRTTIHelperVCLinux
// see linux::SaveCatchVarOpLowering. `_ZTIPv` is also what a `throw e` of the
// caught value throws again.
setI32AsCatchType();
setU32AsCatchType();
setF64AsCatchType();
setF32AsCatchType();
setBoolAsCatchType();
Expand Down Expand Up @@ -247,7 +261,14 @@ class MLIRRTTIHelperVCLinux
auto width = intType.getIntOrFloatBitWidth();
if (width == 32)
{
setI32AsCatchType();
if (intType.isUnsigned())
{
setU32AsCatchType();
}
else
{
setI32AsCatchType();
}
}
else if (width == 64)
{
Expand Down
34 changes: 32 additions & 2 deletions tslang/include/TypeScript/MLIRLogic/MLIRRTTIHelperVCWin32.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,22 @@ class MLIRRTTIHelperVCWin32
throwInfoRef = windows::I32Type::throwInfoRef;
}

void setU32AsCatchType()
{
types.push_back({windows::U32Type::typeName, windows::U32Type::typeInfoRef, windows::U32Type::catchableTypeInfoRef,
windows::U32Type::catchableTypeSize});
types.push_back(boxEntry(windows::U32Type::catchableTypeInfoRef2, windows::U32Type::copyThunk2));

TypeNames toNumber{windows::U32Type::typeName3, windows::U32Type::typeInfoRef3, windows::U32Type::catchableTypeInfoRef3,
windows::F64Type::catchableTypeSize};
toNumber.copyThunk = windows::U32Type::copyThunk3;
toNumber.copyThunkTarget = mlir_ts::NumberType::get(rewriter.getContext());
types.push_back(toNumber);

catchableTypeInfoArrayRef = windows::U32Type::catchableTypeInfoArrayRef;
throwInfoRef = windows::U32Type::throwInfoRef;
}

void setBoolAsCatchType()
{
types.push_back({windows::BoolType::typeName, windows::BoolType::typeInfoRef, windows::BoolType::catchableTypeInfoRef,
Expand Down Expand Up @@ -253,7 +269,14 @@ class MLIRRTTIHelperVCWin32
.Case<mlir::IntegerType>([&](auto intType) {
if (intType.getIntOrFloatBitWidth() == 32)
{
setI32AsCatchType();
if (intType.isUnsigned())
{
setU32AsCatchType();
}
else
{
setI32AsCatchType();
}
}
else if (intType.getIntOrFloatBitWidth() == 64)
{
Expand Down Expand Up @@ -321,7 +344,14 @@ class MLIRRTTIHelperVCWin32
.Case<mlir::IntegerType>([&](auto intType) {
if (intType.getIntOrFloatBitWidth() == 32)
{
setI32AsCatchType();
if (intType.isUnsigned())
{
setU32AsCatchType();
}
else
{
setI32AsCatchType();
}
}
else if (intType.getIntOrFloatBitWidth() == 64)
{
Expand Down
5 changes: 3 additions & 2 deletions tslang/lib/TypeScript/LowerToAffineLoops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1654,14 +1654,15 @@ struct TryOpLowering : public TsPattern<mlir_ts::TryOp>
: /*catch all*/ (mlir::Value)rewriter.create<mlir_ts::NullOp>(loc, mth.getNullType());

// `catch (e: number)` has to take `throw 1` too - an integer literal is an int here - and
// a thrown f32. On Windows their ThrowInfos list a `.N` entry that converts (see
// a thrown u32 or f32. On Windows their ThrowInfos list a `.N` entry that converts (see
// copyThunkPrefix in LLVMRTTIHelperVCWin32Const.h); on the Itanium path the catch lists
// their type_infos as further clauses, accepts any of them, and
// linux::SaveCatchVarOpLowering converts.
SmallVector<mlir::Value> widenedTypeInfos;
if (!tsContext->compileOptions.isWindows && catchVarType && isa<mlir_ts::NumberType>(catchVarType))
{
for (auto typeInfoName : {::typescript::linux::I32Type::typeName, ::typescript::linux::F32Type::typeName})
for (auto typeInfoName : {::typescript::linux::I32Type::typeName, ::typescript::linux::U32Type::typeName,
::typescript::linux::F32Type::typeName})
{
widenedTypeInfos.push_back(rewriter.create<mlir_ts::ConstantOp>(
loc, mth.getRefType(mth.getOpaqueType()), mlir::FlatSymbolRefAttr::get(rewriter.getContext(), typeInfoName)));
Expand Down
23 changes: 17 additions & 6 deletions tslang/lib/TypeScript/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5081,16 +5081,26 @@ struct SaveCatchVarOpLowering : public TsLlvmPattern<mlir_ts::SaveCatchVarOp>
return rewriter.create<LLVM::SIToFPOp>(loc, llvmNumberType, intValue);
},
[&](OpBuilder &, Location) -> mlir::Value {
auto floatTypeInfo = rewriter.create<LLVM::AddressOfOp>(loc, ptrTy, ::typescript::linux::F32Type::typeName);
auto isFloat = rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::eq, typeInfo, floatTypeInfo);
auto uintTypeInfo = rewriter.create<LLVM::AddressOfOp>(loc, ptrTy, ::typescript::linux::U32Type::typeName);
auto isUInt = rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::eq, typeInfo, uintTypeInfo);
return clh.conditionalExpressionLowering(
loc, llvmNumberType, isFloat,
loc, llvmNumberType, isUInt,
[&](OpBuilder &, Location) -> mlir::Value {
auto floatValue = rewriter.create<LLVM::LoadOp>(loc, rewriter.getF32Type(), exceptionInfo);
return rewriter.create<LLVM::FPExtOp>(loc, llvmNumberType, floatValue);
auto uintValue = rewriter.create<LLVM::LoadOp>(loc, th.getI32Type(), exceptionInfo);
return rewriter.create<LLVM::UIToFPOp>(loc, llvmNumberType, uintValue);
},
[&](OpBuilder &, Location) -> mlir::Value {
return rewriter.create<LLVM::LoadOp>(loc, llvmNumberType, exceptionInfo);
auto floatTypeInfo = rewriter.create<LLVM::AddressOfOp>(loc, ptrTy, ::typescript::linux::F32Type::typeName);
auto isFloat = rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::eq, typeInfo, floatTypeInfo);
return clh.conditionalExpressionLowering(
loc, llvmNumberType, isFloat,
[&](OpBuilder &, Location) -> mlir::Value {
auto floatValue = rewriter.create<LLVM::LoadOp>(loc, rewriter.getF32Type(), exceptionInfo);
return rewriter.create<LLVM::FPExtOp>(loc, llvmNumberType, floatValue);
},
[&](OpBuilder &, Location) -> mlir::Value {
return rewriter.create<LLVM::LoadOp>(loc, llvmNumberType, exceptionInfo);
});
});
});
}
Expand Down Expand Up @@ -5135,6 +5145,7 @@ struct SaveCatchVarOpLowering : public TsLlvmPattern<mlir_ts::SaveCatchVarOp>
// each type tslang throws, by the type_info a throw of it carries
SmallVector<std::pair<std::string, mlir::Type>> candidates{
{::typescript::linux::I32Type::typeName, mlir::IntegerType::get(ctx, 32, mlir::IntegerType::Signed)},
{::typescript::linux::U32Type::typeName, mlir::IntegerType::get(ctx, 32, mlir::IntegerType::Unsigned)},
{::typescript::linux::F64Type::typeName, mlir_ts::NumberType::get(ctx)},
{::typescript::linux::F32Type::typeName, mlir::Float32Type::get(ctx)},
{::typescript::linux::BoolType::typeName, mlir_ts::BooleanType::get(ctx)},
Expand Down
7 changes: 7 additions & 0 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6114,6 +6114,13 @@ class MLIRGenImpl
builder.getI32IntegerAttr((int)opCode),
leftExpressionValue, rightExpressionValue);

// `>>>` yields an unsigned 32-bit value; left as a signless i32 it widened to a number
// as signed, and `-1 >>> 0` read -1 instead of 4294967295
if (opCode == SyntaxKind::GreaterThanGreaterThanGreaterThanToken && result.getType() == builder.getI32Type())
{
result = builder.create<mlir_ts::CastOp>(location, builder.getIntegerType(32, /*isSigned=*/false), result);
}

// `+` on strings is the one arithmetic operator that allocates: it becomes
// `ts.StringConcat`, which builds a new string. A receiver takes that reference
// over; `("a" + b).length`, where there is no receiver, gives it back at the end of
Expand Down
3 changes: 3 additions & 0 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ tslang_add_test(NAME test-compile-00-throw-number-untyped-catch COMMAND test-run
tslang_add_test(NAME test-compile-00-catch-untyped-value COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00catch_untyped_value.ts")
tslang_add_test(NAME test-compile-00-throw-bool-bigint COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00throw_bool_bigint.ts")
tslang_add_test(NAME test-compile-00-throw-f32 COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00throw_f32.ts")
tslang_add_test(NAME test-compile-00-throw-u32 COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00throw_u32.ts")
tslang_add_test(NAME test-compile-00-cast-to-f32 COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00cast_to_f32.ts")
tslang_add_test(NAME test-compile-00-instanceof-namespace-narrowing COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00instanceof_namespace_narrowing.ts")
tslang_add_test(NAME test-compile-00-using-nested-scopes COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00using_nested_scopes.ts")
Expand Down Expand Up @@ -823,6 +824,7 @@ tslang_add_test(NAME test-jit-00-throw-number-untyped-catch COMMAND test-runner
tslang_add_test(NAME test-jit-00-catch-untyped-value COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00catch_untyped_value.ts")
tslang_add_test(NAME test-jit-00-throw-bool-bigint COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00throw_bool_bigint.ts")
tslang_add_test(NAME test-jit-00-throw-f32 COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00throw_f32.ts")
tslang_add_test(NAME test-jit-00-throw-u32 COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00throw_u32.ts")
tslang_add_test(NAME test-jit-00-cast-to-f32 COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00cast_to_f32.ts")
tslang_add_test(NAME test-jit-00-instanceof-namespace-narrowing COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00instanceof_namespace_narrowing.ts")
tslang_add_test(NAME test-jit-00-using-nested-scopes COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00using_nested_scopes.ts")
Expand Down Expand Up @@ -1722,6 +1724,7 @@ set(TSLANG_CORPUS
00throw_in_catch.ts
00throw_bool_bigint.ts
00throw_f32.ts
00throw_u32.ts
00throw_inlined.ts
00throw_number_untyped_catch.ts
00to_primitive_ops.ts
Expand Down
Loading
Loading