mirror of
https://github.com/intel/intel-graphics-compiler.git
synced 2025-10-30 08:18:26 +08:00
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:
@ -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) {
|
||||
|
||||
@ -66,6 +66,8 @@ namespace IGC {
|
||||
|
||||
/// Other operators
|
||||
|
||||
bool visitExtractElementInst(ExtractElementInst& I);
|
||||
bool visitInsertElementInst(InsertElementInst& I);
|
||||
bool visitGenIntrinsicInst(GenIntrinsicInst& I);
|
||||
bool visitCallInst(CallInst& I);
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
52
IGC/Compiler/tests/Legalization/arbitrary-integers.ll
Normal file
52
IGC/Compiler/tests/Legalization/arbitrary-integers.ll
Normal 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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user