Legalize insert/extract element operating on arbitrary integer types

Support for SPV_INTEL_arbitrary_precision_integers extension is going to
implemented incrementally. This is the first change that brings us closer
to the full support.
This commit is contained in:
aratajew
2021-08-24 13:20:08 +00:00
committed by igcbot
parent d716c4a8a4
commit 1478211e37
4 changed files with 189 additions and 1 deletions

View File

@ -414,10 +414,144 @@ bool InstPromoter::visitBitCastInst(BitCastInst& I) {
return true;
}
// Promote bitcast with illegal src and dst both requiring to be promoted
// to the same type. Example:
//
// bitcast i12 %v to <3 x i4>
//
// '%v' may just be used as a promoted value, since both i12 and <3 x i4> are
// required to be promoted to i16 type.
if (Act == Promote && ValAct == Promote &&
Val->getType() == TySeq->front()) {
Promoted = Val;
return true;
}
// Unsupported legalization action.
return false;
}
bool InstPromoter::visitExtractElementInst(ExtractElementInst& I) {
ValueSeq* ValSeq; LegalizeAction ValAct;
Value* Val = I.getOperand(0);
std::tie(ValSeq, ValAct) = TL->getLegalizedValues(Val);
if (ValAct != Legal)
Val = ValSeq->front();
TypeSeq* TySeq; LegalizeAction Act;
std::tie(TySeq, Act) = TL->getLegalizedTypes(I.getType());
IGC_ASSERT(Act == Legal || Act == Promote);
auto SetBits = [](uint64_t& Data, uint32_t From, uint32_t To) {
IGC_ASSERT(From < To);
uint64_t N = To - From;
uint64_t Mask = (0xFFFFFFFFFFFFFFFFu >> (64 - N));
Data |= (Mask << From);
};
if (Act == Promote && Val->getType()->isIntegerTy()) {
if (ConstantInt* Index = dyn_cast<ConstantInt>(I.getIndexOperand())) {
const uint32_t IndexImm = int_cast<uint32_t>(Index->getZExtValue());
const uint32_t IllegalElemTyWidth = I.getOperand(0)->getType()->getScalarSizeInBits();
// Mask preparation
uint64_t Mask = 0;
const uint32_t From = IndexImm * IllegalElemTyWidth;
const uint32_t To = From + IllegalElemTyWidth;
SetBits(Mask, From, To);
// Clear bits representing source vector elements that are not queried by
// extract element instruction
Value* And = IRB->CreateAnd(Val, Mask);
// Shift relevant bits to put sign bit on it's place
Type* LegalReturnTy = TySeq->front();
const uint32_t LegalReturnTyWidth = LegalReturnTy->getIntegerBitWidth();
const uint32_t CurrSignPos = To - 1;
const uint32_t TargetSignPos = LegalReturnTyWidth - 1;
Value* Shift = nullptr;
if (CurrSignPos == TargetSignPos) {
// Continue operating on 'and' instruction. Shifting is not required,
// since sign bit is already in place.
Shift = And;
}
else {
if (CurrSignPos < TargetSignPos) {
Shift = IRB->CreateShl(And, TargetSignPos - CurrSignPos);
}
else if (CurrSignPos > TargetSignPos) {
Shift = IRB->CreateLShr(And, CurrSignPos - TargetSignPos);
}
}
// Truncate result to a legalized type
Value* Trunc = IRB->CreateTrunc(Shift, LegalReturnTy);
// Shift bits back to put relevant ones at the begging of an integer
IGC_ASSERT(LegalReturnTyWidth > IllegalElemTyWidth);
Promoted = IRB->CreateAShr(Trunc, LegalReturnTyWidth - IllegalElemTyWidth);
return true;
}
else {
IGC_ASSERT_MESSAGE(0, "Cannot legalize extract element instruction with non-constant index!");
return false;
}
}
return false;
}
bool InstPromoter::visitInsertElementInst(InsertElementInst& I) {
ValueSeq* ValSeq; LegalizeAction ValAct;
Value* Val = I.getOperand(1);
std::tie(ValSeq, ValAct) = TL->getLegalizedValues(Val);
if (ValAct != Legal)
Val = ValSeq->front();
Value* VecVal = I.getOperand(0);
if (!isa<UndefValue>(VecVal)) {
ValueSeq* VecValSeq; LegalizeAction VecValAct;
std::tie(VecValSeq, VecValAct) = TL->getLegalizedValues(VecVal);
if (VecValAct != Legal)
VecVal = VecValSeq->front();
}
TypeSeq* TySeq; LegalizeAction Act;
std::tie(TySeq, Act) = TL->getLegalizedTypes(I.getType());
IGC_ASSERT(Act == Legal || Act == Promote);
if (Act == Promote && Val->getType()->isIntegerTy()) {
if (ConstantInt* Index = dyn_cast<ConstantInt>(I.getOperand(2))) {
// Extend value to be inserted to the legalized insert element return type
Value* ZExt = IRB->CreateZExt(Val, TySeq->front());
// Shift extended value to it's place based on index to imitate insert element behavior
// Note: If an insert element index is zero, we don't need to generate shl instruction.
const uint32_t IllegalElemTyWidth = I.getOperand(0)->getType()->getScalarSizeInBits();
const uint32_t IndexImm = int_cast<uint32_t>(Index->getZExtValue());
const uint32_t ShiftFactor = IndexImm * IllegalElemTyWidth;
Promoted = (IndexImm > 0) ? IRB->CreateShl(ZExt, ShiftFactor) : ZExt;
if (!isa<UndefValue>(VecVal)) {
// Generate 'and' instruction to merge value returned by another insert element instruction
// with value to be inserted.
IGC_ASSERT(VecVal->getType()->isIntegerTy());
Promoted = IRB->CreateAnd(VecVal, Promoted);
}
}
else {
IGC_ASSERT_MESSAGE(0, "Cannot legalize insert element instruction with non-constant index!");
return false;
}
}
return true;
}
/// Other operators
bool InstPromoter::visitGenIntrinsicInst(GenIntrinsicInst& I) {

View File

@ -66,6 +66,8 @@ namespace IGC {
/// Other operators
bool visitExtractElementInst(ExtractElementInst& I);
bool visitInsertElementInst(InsertElementInst& I);
bool visitGenIntrinsicInst(GenIntrinsicInst& I);
bool visitCallInst(CallInst& I);
};

View File

@ -196,7 +196,7 @@ TypeLegalizer::getLegalizedTypes(Type* Ty) {
}
TypeSeq* TypeLegalizer::getPromotedTypeSeq(Type* Ty) {
IGC_ASSERT(Ty->isIntegerTy());
IGC_ASSERT(Ty->isIntOrIntVectorTy());
IGC_ASSERT(getTypeLegalizeAction(Ty) == Promote);
TypeMapTy::iterator TMI; bool New;

View File

@ -0,0 +1,52 @@
;=========================== begin_copyright_notice ============================
;
; Copyright (C) 2017-2021 Intel Corporation
;
; SPDX-License-Identifier: MIT
;
;============================ end_copyright_notice =============================
; RUN: igc_opt %s -S -o - -igc-type-legalizer | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f80:128:128-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-a:64:64-f80:128:128-n8:16:32:64"
%"vec3xi4" = type { <3 x i4> }
; CHECK-LABEL: define void @testExtractElement
define void @testExtractElement(i16) {
%a = trunc i16 %0 to i12
%b = bitcast i12 %a to <3 x i4>
%e0 = extractelement <3 x i4> %b, i32 0
; CHECK: %[[AND:.*]] = and i16 %0, 15
; CHECK: %[[SHL:.*]] = shl i16 %[[AND]], 4
; CHECK: %[[TR:.*]] = trunc i16 %[[SHL]] to i8
; CHECK: %[[E0:.*]] = ashr i8 %[[TR]], 4
%e1 = extractelement <3 x i4> %b, i32 1
; CHECK: %[[AND:.*]] = and i16 %0, 240
; CHECK: %[[TR:.*]] = trunc i16 %[[AND]] to i8
; CHECK: %[[E1:.*]] = ashr i8 %[[TR]], 4
%e2 = extractelement <3 x i4> %b, i32 2
; CHECK: %[[AND:.*]] = and i16 %0, 3840
; CHECK: %[[SHR:.*]] = lshr i16 %[[AND]], 4
; CHECK: %[[TR:.*]] = trunc i16 %[[SHR]] to i8
; CHECK: %[[E2:.*]] = ashr i8 %[[TR]], 4
ret void
}
; CHECK-LABEL: define void @testInsertElement
define void @testInsertElement(i8) {
%a = trunc i8 %0 to i4
%v0 = insertelement <3 x i4> undef, i4 %a, i32 0
; CHECK: %[[V0:.*]] = zext i8 %0 to i16
%v1 = insertelement <3 x i4> %v0, i4 %a, i32 1
; CHECK: %[[ZEXT:.*]] = zext i8 %0 to i16
; CHECK: %[[SHL:.*]] = shl i16 %[[ZEXT]], 4
; CHECK: %[[V1:.*]] = and i16 %[[V0]], %[[SHL]]
%v2 = insertelement <3 x i4> %v1, i4 %a, i32 2
; CHECK: %[[ZEXT:.*]] = zext i8 %0 to i16
; CHECK: %[[SHL:.*]] = shl i16 %[[ZEXT]], 8
; CHECK: %[[V2:.*]] = and i16 %[[V1]], %[[SHL]]
ret void
}