diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -615,6 +615,23 @@ } } break; + case Type::ArrayTyID: { + // if the whole array is 'undef' just reserve memory for the value. + if (ArrayType *ATy = dyn_cast(C->getType())) { + uint64_t elemNum = ATy->getNumElements(); + Result.AggregateVal.resize(elemNum); + Type *ElemTy = ATy->getElementType(); + for (unsigned int i = 0; i < elemNum; ++i) { + if (ElemTy->isIntegerTy()) + Result.AggregateVal[i].IntVal = + APInt(ElemTy->getPrimitiveSizeInBits(), 0); + else if (ElemTy->isAggregateType()) { + const Constant *ElemUndef = UndefValue::get(ElemTy); + Result.AggregateVal[i] = getConstantValue(ElemUndef); + } + } + } + } break; case Type::ScalableVectorTyID: report_fatal_error( "Scalable vector support not yet implemented in ExecutionEngine"); @@ -1005,6 +1022,57 @@ llvm_unreachable("Unknown constant pointer type!"); } break; + case Type::StructTyID: + if (const auto CS = dyn_cast(C)) { + Result.AggregateVal.resize(CS->getType()->getNumElements()); + for (size_t i = 0; i < Result.AggregateVal.size(); ++i) + Result.AggregateVal[i] = + getConstantValue(CS->getAggregateElement((unsigned int)i)); + break; + } + if (const auto CAZ = dyn_cast(C)) { + Result.AggregateVal.resize(CAZ->getElementCount().getKnownMinValue()); + for (size_t i = 0; i < Result.AggregateVal.size(); ++i) + Result.AggregateVal[i] = + getConstantValue(CAZ->getElementValue((unsigned int)i)); + break; + } + llvm_unreachable("Unknown constant struct kind!"); + break; + + case Type::ArrayTyID: + if (const auto CA = dyn_cast(C)) { + Result.AggregateVal.resize(CA->getType()->getNumElements()); + for (size_t i = 0; i < Result.AggregateVal.size(); ++i) + Result.AggregateVal[i] = + getConstantValue(CA->getAggregateElement((unsigned int)i)); + break; + } + if (const auto CDA = dyn_cast(C)) { + Result.AggregateVal.resize(CDA->getNumElements()); + for (size_t i = 0; i < Result.AggregateVal.size(); ++i) + Result.AggregateVal[i] = + getConstantValue(CDA->getAggregateElement((unsigned int)i)); + break; + } + if (const auto CDS = dyn_cast(C)) { + Result.AggregateVal.resize(CDS->getNumElements()); + for (size_t i = 0; i < Result.AggregateVal.size(); ++i) + Result.AggregateVal[i] = + getConstantValue(CDS->getAggregateElement((unsigned int)i)); + break; + } + if (const auto CAZ = dyn_cast(C)) { + Result.AggregateVal.resize(CAZ->getElementCount().getKnownMinValue()); + for (size_t i = 0; i < Result.AggregateVal.size(); ++i) + Result.AggregateVal[i] = + getConstantValue(CAZ->getElementValue((unsigned int)i)); + break; + } + + llvm_unreachable("Unknown constant array kind!"); + break; + default: SmallString<256> Msg; raw_svector_ostream OS(Msg); @@ -1056,6 +1124,31 @@ } } break; + case Type::StructTyID: { + const auto ST = cast(Ty); + const unsigned numElems = ST->getNumElements(); + const StructLayout *const SL = getDataLayout().getStructLayout(ST); + assert(Val.AggregateVal.size() == numElems && + "Unexpected number of elements in AggregateVal"); + for (unsigned i = 0; i < numElems; ++i) { + StoreValueToMemory( + Val.AggregateVal[i], + (GenericValue *)(((uint8_t *)Ptr) + SL->getElementOffset(i)), + ST->getElementType(i)); + } + } break; + case Type::ArrayTyID: { + const auto AT = cast(Ty); + const uint64_t numElems = AT->getNumElements(); + const auto ET = AT->getElementType(); + const auto S = getDataLayout().getTypeAllocSize(ET); + assert(Val.AggregateVal.size() == numElems && + "Unexpected number of elements in AggregateVal"); + for (unsigned i = 0; i < numElems; ++i) { + StoreValueToMemory(Val.AggregateVal[i], + (GenericValue *)(((uint8_t *)Ptr) + i * S), ET); + } + } break; } if (sys::IsLittleEndianHost != getDataLayout().isLittleEndian()) @@ -1121,6 +1214,29 @@ } break; } + case Type::StructTyID: { + const auto ST = cast(Ty); + const unsigned numElems = ST->getNumElements(); + const StructLayout *const SL = getDataLayout().getStructLayout(ST); + Result.AggregateVal.resize(numElems); + for (unsigned i = 0; i < numElems; ++i) { + LoadValueFromMemory( + Result.AggregateVal[i], + (GenericValue *)(((uint8_t *)Ptr) + SL->getElementOffset(i)), + ST->getElementType(i)); + } + } break; + case Type::ArrayTyID: { + const auto AT = cast(Ty); + const uint64_t numElems = AT->getNumElements(); + const auto ET = AT->getElementType(); + const auto S = getDataLayout().getTypeAllocSize(ET); + Result.AggregateVal.resize(numElems); + for (unsigned i = 0; i < numElems; ++i) { + LoadValueFromMemory(Result.AggregateVal[i], + (GenericValue *)(((uint8_t *)Ptr) + i * S), ET); + } + } break; default: SmallString<256> Msg; raw_svector_ostream OS(Msg); diff --git a/test/ExecutionEngine/Interpreter/composite-load-store.ll b/test/ExecutionEngine/Interpreter/composite-load-store.ll new file mode 100644 --- /dev/null +++ b/test/ExecutionEngine/Interpreter/composite-load-store.ll @@ -0,0 +1,102 @@ +; RUN: %lli -jit-kind=mcjit -force-interpreter %s + +%"SomeStruct" = type { i1, [ 2 x i32 ], double } + +define void @load_test() +{ + %s_ptr = alloca %"SomeStruct" + + ; Store separate elements. + %s_ptr.0 = getelementptr %"SomeStruct", ptr %s_ptr, i32 0, i32 0 + %s_ptr.1.0 = getelementptr %"SomeStruct", ptr %s_ptr, i32 0, i32 1, i32 0 + %s_ptr.1.1 = getelementptr %"SomeStruct", ptr %s_ptr, i32 0, i32 1, i32 1 + %s_ptr.2 = getelementptr %"SomeStruct", ptr %s_ptr, i32 0, i32 2 + + store i1 true, ptr %s_ptr.0 + store i32 10, ptr %s_ptr.1.0 + store i32 20, ptr %s_ptr.1.1 + store double 3.14, ptr %s_ptr.2 + + ; Load whole struct. + %s = load %"SomeStruct", ptr %s_ptr + + ; Extract separate elements. + %s.0 = extractvalue %"SomeStruct" %s, 0 + %s.1.0 = extractvalue %"SomeStruct" %s, 1, 0 + %s.1.1 = extractvalue %"SomeStruct" %s, 1, 1 + %s.2 = extractvalue %"SomeStruct" %s, 2 + + ; Compare extracted values with expected. + %s_cmp.0 = icmp eq i1 %s.0, true + %s_cmp.1.0 = icmp eq i32 %s.1.0, 10 + %s_cmp.1.1 = icmp eq i32 %s.1.1, 20 + %s_cmp.2 = fcmp oeq double %s.2, 3.14 + + ; Break to error label if extracted value is unexpected. + br i1 %s_cmp.0, label %s_cmp_ok.0, label %on_error +s_cmp_ok.0: + + br i1 %s_cmp.1.0, label %s_cmp_ok.1.0, label %on_error +s_cmp_ok.1.0: + + br i1 %s_cmp.1.1, label %s_cmp_ok.1.1, label %on_error +s_cmp_ok.1.1: + + br i1 %s_cmp.2, label %s_cmp_ok.2, label %on_error +s_cmp_ok.2: + + ret void + +on_error: + unreachable +} + +define void @store_test() +{ + %s_ptr = alloca %"SomeStruct" + + ; Store some constant as whole. + store %"SomeStruct"{ i1 true, [ 2 x i32 ] [ i32 10, i32 20 ], double 3.14 }, ptr %s_ptr + + ; Load elements of stored value. + %s_ptr.0 = getelementptr %"SomeStruct", ptr %s_ptr, i32 0, i32 0 + %s_ptr.1.0 = getelementptr %"SomeStruct", ptr %s_ptr, i32 0, i32 1, i32 0 + %s_ptr.1.1 = getelementptr %"SomeStruct", ptr %s_ptr, i32 0, i32 1, i32 1 + %s_ptr.2 = getelementptr %"SomeStruct", ptr %s_ptr, i32 0, i32 2 + + %s.0 = load i1, ptr %s_ptr.0 + %s.1.0 = load i32, ptr %s_ptr.1.0 + %s.1.1 = load i32, ptr %s_ptr.1.1 + %s.2 = load double, ptr %s_ptr.2 + + ; Compare loaded values with expected. + %s_cmp.0 = icmp eq i1 %s.0, true + %s_cmp.1.0 = icmp eq i32 %s.1.0, 10 + %s_cmp.1.1 = icmp eq i32 %s.1.1, 20 + %s_cmp.2 = fcmp oeq double %s.2, 3.14 + + ; Break to error label if loaded value is unexpected. + br i1 %s_cmp.0, label %s_cmp_ok.0, label %on_error +s_cmp_ok.0: + + br i1 %s_cmp.1.0, label %s_cmp_ok.1.0, label %on_error +s_cmp_ok.1.0: + + br i1 %s_cmp.1.1, label %s_cmp_ok.1.1, label %on_error +s_cmp_ok.1.1: + + br i1 %s_cmp.2, label %s_cmp_ok.2, label %on_error +s_cmp_ok.2: + + ret void + +on_error: + unreachable +} + +define i32 @main() +{ + call void @load_test() + call void @store_test() + ret i32 0 +} \ No newline at end of file