diff --git a/tslang/include/TypeScript/LowerToLLVM/CastLogicHelper.h b/tslang/include/TypeScript/LowerToLLVM/CastLogicHelper.h index 924e8a976..bb2327ede 100644 --- a/tslang/include/TypeScript/LowerToLLVM/CastLogicHelper.h +++ b/tslang/include/TypeScript/LowerToLLVM/CastLogicHelper.h @@ -106,9 +106,11 @@ class CastLogicHelper return castIntToString(in, tch.getIndexTypeBitwidth(), true); } + // a sign-neutral iN prints signed, as it compares and converts to number: `let a: i32 = -1` is -1, + // not 4294967295; only an unsigned uN prints unsigned if (isa(inType) && isResString) { - return castIntToString(in, inLLVMType.getIntOrFloatBitWidth(), inType.isSignedInteger()); + return castIntToString(in, inLLVMType.getIntOrFloatBitWidth(), !inType.isUnsignedInteger()); } // a bigint is a signed i64; without this case it fell through to a bare inttoptr, and @@ -151,17 +153,16 @@ class CastLogicHelper } } - // a signed integer keeps its sign as an index: `let n = s.length; n = -1` held 4294967295 under the - // zext in castLLVMTypesLogic - if (inType.isSignedInteger() && resType.isIndex() && resLLVMType.getIntOrFloatBitWidth() > inType.getIntOrFloatBitWidth()) + // a wider integer keeps the value: a signed or sign-neutral (iN) one sign-extends, only an unsigned one + // zero-extends (castLLVMTypesLogic, which sees signless LLVM types only). `let c: i64 = -7` held + // 4294967289, `let n = s.length; n = -1` held 4294967295, and `i16` -300 compared as 65236. + if (auto inIntType = dyn_cast(inType)) { - return rewriter.create(loc, resLLVMType, in); - } - - // TODO: should be in LLVM cast? - if (inType.isSignedInteger() && resType.isSignedInteger() && resType.getIntOrFloatBitWidth() > inType.getIntOrFloatBitWidth()) - { - return rewriter.create(loc, resLLVMType, in); + if (!inIntType.isUnsigned() && inIntType.getWidth() > 1 && (isa(resType) || resType.isIndex()) + && resLLVMType.getIntOrFloatBitWidth() > inLLVMType.getIntOrFloatBitWidth()) + { + return rewriter.create(loc, resLLVMType, in); + } } // an unsigned integer is converted to a float as unsigned: castLLVMTypesLogic only sees the diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index aa0e701aa..9eb446104 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -398,6 +398,7 @@ tslang_add_test(NAME test-compile-00-generator-return COMMAND test-runner "${PRO tslang_add_test(NAME test-compile-00-return-inference-undefined COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00return_inference_undefined.ts") tslang_add_test(NAME test-compile-00-return-falls-off-end COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00return_falls_off_end.ts") tslang_add_test(NAME test-compile-00-nullish-values COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00nullish_values.ts") +tslang_add_test(NAME test-compile-00-signless-int-signed COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00signless_int_signed.ts") tslang_add_test(NAME test-compile-00-intersection-type COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00intersection_type.ts") tslang_add_test(NAME test-compile-00-intersection-type-generic COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00intersection_type_generic.ts") tslang_add_test(NAME test-compile-00-length COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00length.ts") @@ -879,6 +880,7 @@ tslang_add_test(NAME test-jit-00-generator-return COMMAND test-runner -jit "${PR tslang_add_test(NAME test-jit-00-return-inference-undefined COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00return_inference_undefined.ts") tslang_add_test(NAME test-jit-00-return-falls-off-end COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00return_falls_off_end.ts") tslang_add_test(NAME test-jit-00-nullish-values COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00nullish_values.ts") +tslang_add_test(NAME test-jit-00-signless-int-signed COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00signless_int_signed.ts") tslang_add_test(NAME test-jit-00-union-global-init COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00union_global_init.ts") tslang_add_test(NAME test-jit-00-intersection-type COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00intersection_type.ts") tslang_add_test(NAME test-jit-00-intersection-type-generic COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00intersection_type_generic.ts") diff --git a/tslang/test/tester/tests/00signless_int_signed.ts b/tslang/test/tester/tests/00signless_int_signed.ts new file mode 100644 index 000000000..973cdea99 --- /dev/null +++ b/tslang/test/tester/tests/00signless_int_signed.ts @@ -0,0 +1,41 @@ +// a sign-neutral iN is signed: it prints, widens and compares keeping its sign (`let a: i32 = -1` printed +// 4294967295, `let c: i64 = -7` held 4294967289, `i16` -300 compared as 65236); a uN stays unsigned +function main() { + let a: i32 = -1; + assert(`${a}` == "-1", "i32 prints signed"); + assert(a < 0, "i32 compares signed"); + const n: number = a; + assert(n == -1, "i32 to number"); + + let b: i8 = -5; + assert(`${b}` == "-5", "i8 prints signed"); + + let c: i64 = -7; + assert(`${c}` == "-7", "i32 literal widens to i64 with its sign"); + assert(c < 0, "i64 compares signed"); + + let d: i16 = -300; + assert(d < 0, "i16 widens to compare with its sign"); + assert(`${d}` == "-300", "i16 prints signed"); + + const x: any = a; + assert(`${x}` == "-1", "i32 in any"); + + let k: i32 = -2; + let m: index = k; + assert(`${m}` == "-2", "i32 widens to index with its sign"); + + let big: i64 = -9000000000; + assert(`${big}` == "-9000000000" && big < 0, "i64"); + + // unsigned stays unsigned + let u: u32 = 4294967295; + assert(`${u}` == "4294967295", "u32 prints unsigned"); + let u8v: u8 = 255; + let widened: s32 = u8v; + assert(widened == 255, "u8 widens with zeros"); + let e: i64 = u; + assert(`${e}` == "4294967295", "u32 widens to i64 with zeros"); + + print("done."); +}