Skip to content

Commit

Permalink
Fix generation of <4 x i8> constants
Browse files Browse the repository at this point in the history
Cover both when all components are int constants, or
when some are undef values.

Fixes google#36
  • Loading branch information
dneto0 committed Aug 26, 2017
1 parent 391aeb1 commit 49351ac
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 9 deletions.
54 changes: 46 additions & 8 deletions lib/SPIRVProducerPass.cpp
Expand Up @@ -1936,6 +1936,44 @@ void SPIRVProducerPass::GenerateSPIRVConstants() {

} else if (const ConstantDataSequential *CDS =
dyn_cast<ConstantDataSequential>(Cst)) {
// Let's convert <4 x i8> constant to int constant specially.
// This case occurs when all the values are specified as constant
// ints.
Type *CstTy = Cst->getType();
if (is4xi8vec(CstTy)) {
LLVMContext &Context = CstTy->getContext();

//
// Generate OpConstant with OpTypeInt 32 0.
//
uint64_t IntValue = 0;
for (int i = 0; i < 4; i++) {
const uint64_t Val = CDS->getElementAsInteger(i);
IntValue = (IntValue << 8) | (Val & 0xffu);
}

Type *i32 = Type::getInt32Ty(Context);
Constant *CstInt = ConstantInt::get(i32, IntValue);
// If this constant is already registered on VMap, use it.
if (VMap.count(CstInt)) {
uint32_t CstID = VMap[CstInt];
VMap[Cst] = CstID;
continue;
}

LiteralNum.push_back(IntValue);
SPIRVOperand *CstValue =
new SPIRVOperand(SPIRVOperandType::LITERAL_INTEGER, LiteralNum);
Ops.push_back(CstValue);

SPIRVInstruction *CstInst =
new SPIRVInstruction(4, spv::OpConstant, nextID++, Ops);
SPIRVInstList.push_back(CstInst);

continue;
}

// A normal constant-data-sequential case.
for (unsigned k = 0; k < CDS->getNumElements(); k++) {
Constant *EleCst = CDS->getElementAsConstant(k);
uint32_t EleCstID = VMap[EleCst];
Expand All @@ -1948,6 +1986,7 @@ void SPIRVProducerPass::GenerateSPIRVConstants() {
WordCount = static_cast<uint16_t>(3 + CDS->getNumElements());
} else if (const ConstantAggregate *CA = dyn_cast<ConstantAggregate>(Cst)) {
// Let's convert <4 x i8> constant to int constant specially.
// This case occurs when at least one of the values is an undef.
Type *CstTy = Cst->getType();
if (is4xi8vec(CstTy)) {
LLVMContext &Context = CstTy->getContext();
Expand All @@ -1960,22 +1999,23 @@ void SPIRVProducerPass::GenerateSPIRVConstants() {
for (User::const_op_iterator I = Cst->op_begin(), E = Cst->op_end();
I != E; ++I) {
uint64_t Val = 0;
if (ConstantInt *CI2 = dyn_cast<ConstantInt>(I)) {
Val = CI2->getZExtValue();
const Value* CV = *I;
if (auto* CI = dyn_cast<ConstantInt>(CV)) {
Val = CI->getZExtValue();
}
IntValue = (IntValue << Idx) | Val;
IntValue = (IntValue << 8) | (Val & 0xffu);
}

ConstantInt *CstInt =
ConstantInt::get(Type::getInt32Ty(Context), IntValue);
Type *i32 = Type::getInt32Ty(Context);
Constant *CstInt = ConstantInt::get(i32, IntValue);
// If this constant is already registered on VMap, use it.
if (VMap.count(CstInt)) {
uint32_t CstID = VMap[CstInt];
VMap[Cst] = CstID;
continue;
}

LiteralNum.push_back(IntValue & 0xFFFFFFFF);
LiteralNum.push_back(IntValue);
SPIRVOperand *CstValue =
new SPIRVOperand(SPIRVOperandType::LITERAL_INTEGER, LiteralNum);
Ops.push_back(CstValue);
Expand All @@ -1987,8 +2027,6 @@ void SPIRVProducerPass::GenerateSPIRVConstants() {
continue;
}

// This is a normal constant aggregate.

// We use a constant composite in SPIR-V for our constant aggregate in
// LLVM.
Opcode = spv::OpConstantComposite;
Expand Down
8 changes: 7 additions & 1 deletion test/Structs/insert_value_issue_14.cl
Expand Up @@ -3,6 +3,9 @@
// of an early return in constant generation when we generate
// the <4 x i8> constant.

// Also test https://github.com/google/clspv/issues/36 for
// generation of the <4 x i8> constant including an undef component.

typedef struct {
int a, b, c, d;
} S;
Expand All @@ -26,5 +29,8 @@ kernel void foo(global S* A, global uchar4* B, int n) {


// CHECK: [[uint:%[_a-zA-Z0-9]+]] = OpTypeInt 32 0
// CHECK: [[struct:%[_a-zA-Z0-9]+]] = OpTypeStruct [[uint]] [[uint]] [[uint]] [[uint]]
// CHECK: [[struct:%[_a-zA-Z0-9]+]] = OpTypeStruct [[uint]] [[uint]] [[uint]]
// With undef mapping to 0 byte, (undef,1,2,3) maps to 66051.
// CHECK: [[theconst:%[_a-zA-Z0-9]+]] = OpConstant [[uint]] 66051
// CHECK: [[undef_struct:%[_a-zA-Z0-9]+]] = OpUndef [[struct]]
// CHECK: OpBitwiseAnd [[uint]] [[theconst]] {{%[_a-zA-Z0-9]+}}
20 changes: 20 additions & 0 deletions test/char4_constant.cl
@@ -0,0 +1,20 @@

// Test for https://github.com/google/clspv/issues/36
// A <4 x 18> constant was generated incorrectly.

kernel void dup(global uchar4 *B) {
*B = (uchar4)(1,128,3,4);
}

// RUN: clspv %s -S -o %t.spvasm
// RUN: FileCheck %s < %t.spvasm
// RUN: clspv %s -o %t.spv
// RUN: spirv-dis -o %t2.spvasm %t.spv
// RUN: FileCheck %s < %t2.spvasm
// RUN: spirv-val --target-env vulkan1.0 %t.spv


// CHECK: [[uint:%[_a-zA-Z0-9]+]] = OpTypeInt 32 0
// CHECK: [[theconst:%[_a-zA-Z0-9]+]] = OpConstant [[uint]] 25166596
// CHECK-DAG: OpStore {{%[_a-zA-Z0-9]+}} [[theconst]]
// CHECK-NOT: OpStore
20 changes: 20 additions & 0 deletions test/char4_constant_zero.cl
@@ -0,0 +1,20 @@

// Test for https://github.com/google/clspv/issues/36
// A <4 x 18> constant was generated incorrectly.

kernel void dup(global uchar4 *B) {
*B = (uchar4)(0,0,0,0);
}

// RUN: clspv %s -S -o %t.spvasm
// RUN: FileCheck %s < %t.spvasm
// RUN: clspv %s -o %t.spv
// RUN: spirv-dis -o %t2.spvasm %t.spv
// RUN: FileCheck %s < %t2.spvasm
// RUN: spirv-val --target-env vulkan1.0 %t.spv


// CHECK: [[uint:%[_a-zA-Z0-9]+]] = OpTypeInt 32 0
// CHECK: [[theconst:%[_a-zA-Z0-9]+]] = OpConstantNull [[uint]]
// CHECK-DAG: OpStore {{%[_a-zA-Z0-9]+}} [[theconst]]
// CHECK-NOT: OpStore

0 comments on commit 49351ac

Please sign in to comment.