From 7789e2c87c8a577c65e661ca689b34f9140da117 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Wed, 20 May 2020 06:31:36 -0700 Subject: [PATCH 1/3] IRGen: Fix enumPayload value witness emission for huge types LLVM's isel does not like integer types beyond a certain size (llvm::IntegerType::MAX_INT_BITS). rdar://63189452 --- lib/IRGen/GenType.cpp | 53 ++++++++++++++++++++++++--------- test/IRGen/Inputs/huge_c_type.h | 31 +++++++++++++++++++ test/IRGen/huge_c_type.swift | 11 +++++++ 3 files changed, 81 insertions(+), 14 deletions(-) create mode 100644 test/IRGen/Inputs/huge_c_type.h create mode 100644 test/IRGen/huge_c_type.swift diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 4dfd535594683..7c8423d1f357b 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -687,15 +687,26 @@ llvm::Value *irgen::getFixedTypeEnumTagSinglePayload( llvm::Value *caseIndexFromValue = zero; if (fixedSize > Size(0)) { - // Read up to one pointer-sized 'chunk' of the payload. - // The size of the chunk does not have to be a power of 2. - auto *caseIndexType = llvm::IntegerType::get(Ctx, - fixedSize.getValueInBits()); - auto *caseIndexAddr = Builder.CreateBitCast(valueAddr, - caseIndexType->getPointerTo()); - caseIndexFromValue = Builder.CreateZExtOrTrunc( - Builder.CreateLoad(Address(caseIndexAddr, Alignment(1))), - IGM.Int32Ty); + // llvm only supports integer types upto a certain size (i.e selection dag + // will crash). + if (fixedSize.getValueInBits() <= llvm::IntegerType::MAX_INT_BITS / 4) { + // Read up to one pointer-sized 'chunk' of the payload. + // The size of the chunk does not have to be a power of 2. + auto *caseIndexType = + llvm::IntegerType::get(Ctx, fixedSize.getValueInBits()); + auto *caseIndexAddr = + Builder.CreateBitCast(valueAddr, caseIndexType->getPointerTo()); + caseIndexFromValue = Builder.CreateZExtOrTrunc( + Builder.CreateLoad(Address(caseIndexAddr, Alignment(1))), + IGM.Int32Ty); + } else { + auto *caseIndexType = llvm::IntegerType::get(Ctx, 32); + auto *caseIndexAddr = + Builder.CreateBitCast(valueAddr, caseIndexType->getPointerTo()); + caseIndexFromValue = Builder.CreateZExtOrTrunc( + Builder.CreateLoad(Address(caseIndexAddr, Alignment(1))), + IGM.Int32Ty); + } } auto *result1 = Builder.CreateAdd( @@ -867,11 +878,25 @@ void irgen::storeFixedTypeEnumTagSinglePayload( payloadIndex->addIncoming(payloadIndex0, payloadLT4BB); if (fixedSize > Size(0)) { - // Write the value to the payload as a zero extended integer. - auto *intType = Builder.getIntNTy(fixedSize.getValueInBits()); - Builder.CreateStore( - Builder.CreateZExtOrTrunc(payloadIndex, intType), - Builder.CreateBitCast(valueAddr, intType->getPointerTo())); + if (fixedSize.getValueInBits() <= llvm::IntegerType::MAX_INT_BITS / 4) { + // Write the value to the payload as a zero extended integer. + auto *intType = Builder.getIntNTy(fixedSize.getValueInBits()); + Builder.CreateStore( + Builder.CreateZExtOrTrunc(payloadIndex, intType), + Builder.CreateBitCast(valueAddr, intType->getPointerTo())); + } else { + // Write the value to the payload as a zero extended integer. + Size limit = IGM.getPointerSize(); + auto *intType = Builder.getIntNTy(limit.getValueInBits()); + Builder.CreateStore( + Builder.CreateZExtOrTrunc(payloadIndex, intType), + Builder.CreateBitCast(valueAddr, intType->getPointerTo())); + // Zero the remainder of the payload. + auto zeroAddr = Builder.CreateConstByteArrayGEP(valueAddr, limit); + auto zeroSize = Builder.CreateSub( + size, llvm::ConstantInt::get(size->getType(), limit.getValue())); + Builder.CreateMemSet(zeroAddr, Builder.getInt8(0), zeroSize); + } } // Write to the extra tag bytes, if any. emitSetTag(IGF, extraTagBitsAddr, extraTagIndex, numExtraTagBytes); diff --git a/test/IRGen/Inputs/huge_c_type.h b/test/IRGen/Inputs/huge_c_type.h new file mode 100644 index 0000000000000..42b2a9d7be35b --- /dev/null +++ b/test/IRGen/Inputs/huge_c_type.h @@ -0,0 +1,31 @@ +#include + +typedef uint8_t bool; + +#define CREATE_ARRAY(T, N) \ + struct { \ + T data[N]; \ + size_t size; \ + } + +typedef struct { + int32_t a; + double b[16]; +} Thing; + +typedef struct { + uint64_t a; + bool b; + CREATE_ARRAY(Thing, 16) c; + uint32_t d; + uint64_t e; + uint64_t f; + CREATE_ARRAY(uint32_t, 4) g; + CREATE_ARRAY(uint64_t, 4) h; + CREATE_ARRAY(uint64_t, 4) i; +} Thing2; + +typedef struct { + int64_t a; + CREATE_ARRAY(Thing2, 512) c; +} Thing3; diff --git a/test/IRGen/huge_c_type.swift b/test/IRGen/huge_c_type.swift new file mode 100644 index 0000000000000..93d969726f6da --- /dev/null +++ b/test/IRGen/huge_c_type.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -import-objc-header %S/Inputs/huge_c_type.h %s -disable-llvm-optzns -emit-ir | %FileCheck %s +// Make sure that this does not crash during LLVM's ISel. It does not like huge +// llvm::IntegerTypes. +// RUN: %target-swift-frontend -import-objc-header %S/Inputs/huge_c_type.h %s -c + + +// CHECK-NOT:i9535616 + +public func doIt(a: Thing3) { + print(a) +} From 097e451fbed08d788af1f8c36007841dd923f63d Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Wed, 20 May 2020 11:11:43 -0700 Subject: [PATCH 2/3] Test does not work on linux --- test/IRGen/huge_c_type.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/test/IRGen/huge_c_type.swift b/test/IRGen/huge_c_type.swift index 93d969726f6da..402d3e437d63a 100644 --- a/test/IRGen/huge_c_type.swift +++ b/test/IRGen/huge_c_type.swift @@ -3,6 +3,7 @@ // llvm::IntegerTypes. // RUN: %target-swift-frontend -import-objc-header %S/Inputs/huge_c_type.h %s -c +// REQUIRES: OS=macosx || OS=ios // CHECK-NOT:i9535616 From 940a6d78fd98436371b4c831aab008d05934f6eb Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Wed, 20 May 2020 16:58:45 -0700 Subject: [PATCH 3/3] Try renabling test on all platforms --- test/IRGen/Inputs/huge_c_type.h | 2 +- test/IRGen/huge_c_type.swift | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test/IRGen/Inputs/huge_c_type.h b/test/IRGen/Inputs/huge_c_type.h index 42b2a9d7be35b..2afde356161e4 100644 --- a/test/IRGen/Inputs/huge_c_type.h +++ b/test/IRGen/Inputs/huge_c_type.h @@ -5,7 +5,7 @@ typedef uint8_t bool; #define CREATE_ARRAY(T, N) \ struct { \ T data[N]; \ - size_t size; \ + uint64_t size; \ } typedef struct { diff --git a/test/IRGen/huge_c_type.swift b/test/IRGen/huge_c_type.swift index 402d3e437d63a..ebbed0263aeda 100644 --- a/test/IRGen/huge_c_type.swift +++ b/test/IRGen/huge_c_type.swift @@ -3,8 +3,6 @@ // llvm::IntegerTypes. // RUN: %target-swift-frontend -import-objc-header %S/Inputs/huge_c_type.h %s -c -// REQUIRES: OS=macosx || OS=ios - // CHECK-NOT:i9535616 public func doIt(a: Thing3) {