diff --git a/llvm/lib/ExecutionEngine/ExecutionEngine.cpp b/llvm/lib/ExecutionEngine/ExecutionEngine.cpp --- a/llvm/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/llvm/lib/ExecutionEngine/ExecutionEngine.cpp @@ -615,6 +615,17 @@ } } break; + case Type::ArrayTyID: { + // if the whole array is 'undef' + const ArrayType *ATy = dyn_cast(C->getType()); + unsigned elemNum = ATy->getNumElements(); + Result.AggregateVal.resize(elemNum); + // Go over all a elements and get 'undef' + // constant value for each of them independently. + for (unsigned i = 0; i < elemNum; ++i) + Result.AggregateVal[i] = + getConstantValue(UndefValue::get(ATy->getElementType())); + } break; case Type::ScalableVectorTyID: report_fatal_error( "Scalable vector support not yet implemented in ExecutionEngine"); @@ -1004,7 +1015,47 @@ } llvm_unreachable("Unknown constant pointer type!"); } break; + case Type::StructTyID: { + assert((isa(C) || isa(C)) && + "Invalid constant type."); + const ConstantStruct *CS = dyn_cast(C); + const StructType *CSTy = dyn_cast(C->getType()); + + Result.AggregateVal.resize(CSTy->getNumElements()); + for (unsigned int i = 0; i < CSTy->getNumElements(); ++i) { + // if we have 'zero' constant then we have to create 'zero' + // constant of element type and run getConstantValue recursively + const Constant *opConst = + dyn_cast(C) != 0 + ? Constant::getNullValue(CSTy->getElementType(i)) + : CS->getOperand(i); + Result.AggregateVal[i] = getConstantValue(opConst); + } + } break; + case Type::ArrayTyID: { + assert((isa(C) || isa(C) || + isa(C)) && + "Invalid constant type."); + const ConstantArray *CA = dyn_cast(C); + const ConstantDataArray *CDA = dyn_cast(C); + const ConstantAggregateZero *CAZ = dyn_cast(C); + const ArrayType *CATy = dyn_cast(C->getType()); + auto NumElements = CATy->getNumElements(); + Result.AggregateVal.resize(NumElements); + if (CA) + for (unsigned int i = 0; i < NumElements; ++i) + Result.AggregateVal[i] = getConstantValue(CA->getOperand(i)); + else if (CDA) + for (unsigned int i = 0; i < NumElements; ++i) + Result.AggregateVal[i] = getConstantValue(CDA->getElementAsConstant(i)); + else if (CAZ) + for (unsigned int i = 0; i < NumElements; ++i) + Result.AggregateVal[i] = + getConstantValue(Constant::getNullValue(CATy->getElementType())); + else + llvm_unreachable("Unknown constant array type!"); + } break; default: SmallString<256> Msg; raw_svector_ostream OS(Msg); @@ -1050,12 +1101,42 @@ if (cast(Ty)->getElementType()->isFloatTy()) *(((float*)Ptr)+i) = Val.AggregateVal[i].FloatVal; if (cast(Ty)->getElementType()->isIntegerTy()) { + // getBitWidth() returns number of bits for integer value, but memory + // is allocated in bytes i.e. 8-bit pieces. So if integer type is i5 + // (5-bit), we allocate 8-bit to store values of that type anyway. + // To calculate the size of integer value in bytes we use the + // trick with integer division. Thus we get the minimum number of + // bytes capable to hold getBitWidth() bits. unsigned numOfBytes =(Val.AggregateVal[i].IntVal.getBitWidth()+7)/8; StoreIntToMemory(Val.AggregateVal[i].IntVal, (uint8_t*)Ptr + numOfBytes*i, numOfBytes); } } break; + case Type::StructTyID: { + StructType *STy = dyn_cast(Ty); + const StructLayout *SLO = getDataLayout().getStructLayout(STy); + + for (unsigned i = 0; i < Val.AggregateVal.size(); ++i) { + // calculate offset for the current element + unsigned int offset = SLO->getElementOffset(i); + StoreValueToMemory(Val.AggregateVal[i], + (GenericValue *)((uint8_t *)Ptr + offset), + STy->getElementType(i)); + } + } break; + case Type::ArrayTyID: { + const ArrayType *ATy = dyn_cast(Ty); + + for (unsigned i = 0; i < Val.AggregateVal.size(); ++i) { + // calculate offset for the current element + unsigned int offset = + getDataLayout().getTypeStoreSize(ATy->getElementType()) * i; + StoreValueToMemory(Val.AggregateVal[i], + (GenericValue *)((uint8_t *)Ptr + offset), + ATy->getElementType()); + } + } break; } if (sys::IsLittleEndianHost != getDataLayout().isLittleEndian()) @@ -1116,11 +1197,43 @@ intZero.IntVal = APInt(elemBitWidth, 0); Result.AggregateVal.resize(numElems, intZero); for (unsigned i = 0; i < numElems; ++i) + // getBitWidth() returns number of bits for integer value, but memory + // is allocated in bytes i.e. 8-bit pieces. So if integer type is i5 + // (5-bit), we allocate 8-bit to store values of that type anyway. + // To calculate the size of integer value in bytes we use the + // trick with integer division. Thus we get the minimum number of + // bytes capable to hold getBitWidth() bits. LoadIntFromMemory(Result.AggregateVal[i].IntVal, (uint8_t*)Ptr+((elemBitWidth+7)/8)*i, (elemBitWidth+7)/8); } break; } + case Type::StructTyID: { + StructType *STy = dyn_cast(Ty); + const StructLayout *SLO = getDataLayout().getStructLayout(STy); + + Result.AggregateVal.resize(STy->getNumElements()); + for (unsigned i = 0; i < Result.AggregateVal.size(); ++i) { + // calculate offset for the current element + unsigned int offset = SLO->getElementOffset(i); + LoadValueFromMemory(Result.AggregateVal[i], + (GenericValue *)((uint8_t *)Ptr + offset), + STy->getElementType(i)); + } + } break; + case Type::ArrayTyID: { + const ArrayType *ATy = dyn_cast(Ty); + + Result.AggregateVal.resize(ATy->getNumElements()); + for (unsigned i = 0; i < Result.AggregateVal.size(); ++i) { + // calculate offset for the current element + unsigned int offset = + getDataLayout().getTypeStoreSize(ATy->getElementType()) * i; + LoadValueFromMemory(Result.AggregateVal[i], + (GenericValue *)((uint8_t *)Ptr + offset), + ATy->getElementType()); + } + } break; default: SmallString<256> Msg; raw_svector_ostream OS(Msg); diff --git a/llvm/test/ExecutionEngine/test-interp-aggregate.ll b/llvm/test/ExecutionEngine/test-interp-aggregate.ll new file mode 100644 --- /dev/null +++ b/llvm/test/ExecutionEngine/test-interp-aggregate.ll @@ -0,0 +1,22 @@ +; RUN: %lli -O0 -force-interpreter=true %s + +@U = global [2 x i32] [i32 42, i32 4] +@V = global {i32, i32} zeroinitializer +@W = global [2 x i32] undef + +define i32 @main() { + %1 = load [2 x i32], [2 x i32]* @U + %2 = extractvalue [2 x i32] %1, 0 + %3 = extractvalue [2 x i32] %1, 1 + %4 = add i32 %2, %3 + %5 = sub i32 %4, 46 + %6 = load {i32, i32}, {i32, i32}* @V + %7 = extractvalue {i32, i32} %6, 0 + %8 = extractvalue {i32, i32} %6, 1 + %9 = sub i32 %5, %7 + %10 = sub i32 %9, %8 + %11 = insertvalue {i32, i32} %6, i32 10, 0 + store [2 x i32] %1, [2 x i32]* @W + store {i32, i32} %11, {i32, i32}* @V + ret i32 %10 +} diff --git a/llvm/test/ExecutionEngine/test-interp-vec-insertextractvalue.ll b/llvm/test/ExecutionEngine/test-interp-vec-insertextractvalue.ll --- a/llvm/test/ExecutionEngine/test-interp-vec-insertextractvalue.ll +++ b/llvm/test/ExecutionEngine/test-interp-vec-insertextractvalue.ll @@ -2,6 +2,10 @@ define i32 @main() { + %sa1 = insertvalue [ 2 x i32 ] [i32 1, i32 2], i32 9, 0 + %sa2 = insertvalue [ 2 x i32 ] zeroinitializer, i32 9, 0 + %sa3 = insertvalue [ 2 x i32 ] undef, i32 9, 0 + %s0 = insertvalue { i32, { float, double} } zeroinitializer, i32 9, 0 %s1 = insertvalue { i32, { float, double} } undef, i32 9, 0 %s2 = insertvalue { i32, { float, double} } %s1, float 3.0, 1, 0 %s3 = insertvalue { i32, { float, double} } %s2, double 5.0, 1, 1