Value InterpretedVM::TextureSample(Value sampler, Value coord, Value bias, uint32 resultTypeId) { STypeSampler* samplerType =(STypeSampler*)GetType(sampler.TypeId).Memory; assert(samplerType->Content == 2); assert(ElementCount(coord.TypeId) >= samplerType->Dim + samplerType->Arrayed); Sampler* s = ((Sampler*)sampler.Memory); uint32 index = 0; uint32 acc = 1; for (int d = 0; d < s->DimCount; d++) { uint32 dd = s->Dims[d]; uint32 add = (uint32)(*(float*)IndexMemberValue(coord, d).Memory * (dd - 1) + 0.5f); switch (s->WrapMode) { case WrapMode::WMClamp: add = add < 0 ? 0 : add > dd - 1 ? dd - 1 : add; break; case WrapMode::WMRepeat: add = add % dd; break; } index += add * acc; acc *= dd; } return VmInit(resultTypeId, ((float*)s->Data) + index * 4); }
int start5(char *arg) { int pid; int status; Tconsole("start5(): Running %s\n", TEST); Tconsole("start5(): Pagers: %d, Mappings : %d, Pages: %d, Frames: %d, Children %d, Iterations %d, Priority %d.\n", PAGERS, MAPPINGS, PAGES, FRAMES, CHILDREN, ITERATIONS, PRIORITY); vmRegion = VmInit( MAPPINGS, PAGES, FRAMES, PAGERS ); Spawn("Child", Child, 0,USLOSS_MIN_STACK*7,PRIORITY, &pid); SemP( sem); Wait(&pid, &status); verify(status == 117); Tconsole("start5 done\n"); //PrintStats(); VmDestroy(); Terminate(1); return 0; } /* start5 */
int start5(char *arg) { int pid; int status; Tconsole("start5(): Running: %s\n", TEST); Tconsole("start5(): Pagers: %d\n", PAGERS); Tconsole(" Mappings: %d\n", MAPPINGS); Tconsole(" Pages: %d\n", PAGES); Tconsole(" Frames: %d\n", FRAMES); Tconsole(" Children: %d\n", CHILDREN); Tconsole(" Iterations: %d\n", ITERATIONS); Tconsole(" Priority: %d\n", PRIORITY); status = VmInit( MAPPINGS, PAGES, FRAMES, PAGERS, &vmRegion ); Tconsole("start5(): after call to VmInit, status = %d\n\n", status); assert(status == 0); assert(vmRegion != NULL); SemCreate(0, &sem); Spawn("Child", Child, NULL, USLOSS_MIN_STACK * 7, PRIORITY, &pid); SemP( sem); Wait(&pid, &status); assert(status == 117); Tconsole("start5(): done\n"); //PrintStats(); VmDestroy(); Terminate(1); return 0; } /* start5 */
uint32 InterpretedVM::Execute(Function* func) { prog.CurrentFunction = func; int pc = 0; for (;;) { auto op = func->Ops[pc]; switch (op.Op) { case Op::OpBranch: { auto branch = (SBranch*)op.Memory; pc = func->Labels.at(branch->TargetLabelId); break; } case Op::OpBranchConditional: { auto branch = (SBranchConditional*)op.Memory; uint32 labelID; Value val = Dereference(env.Values[branch->ConditionId]); if (*(bool*)val.Memory) { labelID = branch->TrueLabelId; } else { labelID = branch->FalseLabelId; } pc = func->Labels.at(labelID); break; } case Op::OpFunctionCall: { auto call = (SFunctionCall*)op.Memory; Function toCall = prog.FunctionDefinitions.at(call->FunctionId); for (int i = 0; i < call->ArgumentIdsCount; i++) { env.Values[toCall.Parameters[i].ResultId] = Dereference(env.Values.at(call->ArgumentIds[i])); } uint32 resultId = Execute(&toCall); if (resultId == -1) { return -1; } prog.CurrentFunction = func; env.Values[call->ResultId] = env.Values[resultId]; break; } case Op::OpExtInst: { auto extInst = (SExtInst*)op.Memory; Value* ops = new Value[extInst->OperandIdsCount]; for (int i = 0; i < extInst->OperandIdsCount; i++) { ops[i] = Dereference(env.Values.at(extInst->OperandIds[i])); } ExtInstFunc* func = env.Extensions[extInst->SetId][extInst->Instruction]; env.Values[extInst->ResultId] = func(this, extInst->ResultTypeId, extInst->OperandIdsCount, ops); break; } case Op::OpConvertSToF: { auto convert = (SConvertSToF*)op.Memory; Value op1 = Dereference(env.Values[convert->SignedValueId]); env.Values[convert->ResultId] = DoOp(convert->ResultTypeId, Convert<int32, float>, op1); break; } case Op::OpFAdd: { auto add = (SFAdd*)op.Memory; Value op1 = Dereference(env.Values[add->Operand1Id]); Value op2 = Dereference(env.Values[add->Operand2Id]); env.Values[add->ResultId] = DoOp(add->ResultTypeId, Add<float>, op1, op2); break; } case Op::OpIAdd: { auto add = (SIAdd*)op.Memory; Value op1 = Dereference(env.Values[add->Operand1Id]); Value op2 = Dereference(env.Values[add->Operand2Id]); env.Values[add->ResultId] = DoOp(add->ResultTypeId, Add<int>, op1, op2); break; } case Op::OpFSub: { auto sub = (SFSub*)op.Memory; Value op1 = Dereference(env.Values[sub->Operand1Id]); Value op2 = Dereference(env.Values[sub->Operand2Id]); env.Values[sub->ResultId] = DoOp(sub->ResultTypeId, Sub<float>, op1, op2); break; } case Op::OpISub: { auto sub = (SISub*)op.Memory; Value op1 = Dereference(env.Values[sub->Operand1Id]); Value op2 = Dereference(env.Values[sub->Operand2Id]); env.Values[sub->ResultId] = DoOp(sub->ResultTypeId, Sub<int>, op1, op2); break; } case Op::OpFDiv: { auto div = (SFDiv*)op.Memory; Value op1 = Dereference(env.Values[div->Operand1Id]); Value op2 = Dereference(env.Values[div->Operand2Id]); env.Values[div->ResultId] = DoOp(div->ResultTypeId, Div<float>, op1, op2); break; } case Op::OpFMul: { auto mul = (SFMul*)op.Memory; Value op1 = Dereference(env.Values[mul->Operand1Id]); Value op2 = Dereference(env.Values[mul->Operand2Id]); env.Values[mul->ResultId] = DoOp(mul->ResultTypeId, Mul<float>, op1, op2); break; } case Op::OpIMul: { auto mul = (SFMul*)op.Memory; Value op1 = Dereference(env.Values[mul->Operand1Id]); Value op2 = Dereference(env.Values[mul->Operand2Id]); env.Values[mul->ResultId] = DoOp(mul->ResultTypeId, Mul<int>, op1, op2); break; } case Op::OpVectorTimesScalar: { auto vts = (SVectorTimesScalar*)op.Memory; Value scalar = Dereference(env.Values[vts->ScalarId]); Value vector = Dereference(env.Values[vts->VectorId]); env.Values[vts->ResultId] = DoOp(vts->ResultTypeId, [scalar](Value comp) {return Mul<float>(scalar, comp);}, vector); break; } case Op::OpSLessThan: { auto lessThan = (SSLessThan*)op.Memory; Value op1 = Dereference(env.Values[lessThan->Operand1Id]); Value op2 = Dereference(env.Values[lessThan->Operand2Id]); env.Values[lessThan->ResultId] = DoOp(lessThan->ResultTypeId, [](Value a, Value b) { return Cmp<int32>(a, b) == -1; }, op1, op2); break; } case Op::OpSGreaterThan: { auto greaterThan = (SSLessThan*)op.Memory; Value op1 = Dereference(env.Values[greaterThan->Operand1Id]); Value op2 = Dereference(env.Values[greaterThan->Operand2Id]); env.Values[greaterThan->ResultId] = DoOp(greaterThan->ResultTypeId, [](Value a, Value b) { return Cmp<int32>(a, b) == 1; }, op1, op2); break; } case Op::OpLoad: { auto load = (SLoad*)op.Memory; auto valueToLoad = env.Values.at(load->PointerId); env.Values[load->ResultId] = valueToLoad; break; } case Op::OpStore: { auto store = (SStore*)op.Memory; auto val = env.Values[store->ObjectId]; auto var = GetType(val.TypeId); if (var.Op == Op::OpTypePointer) { SetVariable(store->PointerId, val.Memory); } else { SetVariable(store->PointerId, &val.Memory); } break; } case Op::OpTextureSample: { auto sample = (STextureSample*)op.Memory; auto sampler = Dereference(env.Values.at(sample->SamplerId)); auto coord = Dereference(env.Values.at(sample->CoordinateId)); Value bias = { 0, 0 }; if (sample->BiasId != 0) { bias = Dereference(env.Values.at(sample->BiasId)); } env.Values[sample->ResultId] = TextureSample(sampler, coord, bias, sample->ResultTypeId); break; } case Op::OpLabel: case Op::OpSelectionMerge: case Op::OpLoopMerge: break; case Op::OpAccessChain: { auto access = (SAccessChain*)op.Memory; auto val = Dereference(env.Values.at(access->BaseId)); uint32* indices = new uint32[access->IndexesIdsCount]; for (int i = 0; i < access->IndexesIdsCount; i++) { indices[i] = *(uint32*)Dereference(env.Values[access->IndexesIds[i]]).Memory; } byte* mem = GetPointerInComposite(val.TypeId, val.Memory, access->IndexesIdsCount, indices); delete indices; Value res = VmInit(access->ResultTypeId, &mem); env.Values[access->ResultId] = res; break; } case Op::OpVectorShuffle: { auto vecShuffle = (SVectorShuffle*)op.Memory; auto vec1 = Dereference(env.Values.at(vecShuffle->Vector1Id)); auto vec2 = Dereference(env.Values.at(vecShuffle->Vector2Id)); auto result = VmInit(vecShuffle->ResultTypeId, nullptr); int v1ElCount = ElementCount(vec1.TypeId); for (int i = 0; i < vecShuffle->ComponentsCount; i++) { int index = vecShuffle->Components[i]; Value toCopy; if (index < v1ElCount) { toCopy = vec1; } else { index -= v1ElCount; toCopy = vec2; } Value elToCopy = IndexMemberValue(toCopy, index); memcpy(IndexMemberValue(result, i).Memory, elToCopy.Memory, GetTypeByteSize(elToCopy.TypeId)); } env.Values[vecShuffle->ResultId] = result; break; } //TODO: FIX INDICES (NOT HIERARCHY!) case Op::OpCompositeExtract: { auto extract = (SCompositeExtract*)op.Memory; auto composite = env.Values[extract->CompositeId]; byte* mem = GetPointerInComposite(composite.TypeId, composite.Memory, extract->IndexesCount, extract->Indexes); Value val = { extract->ResultTypeId, VmAlloc(extract->ResultTypeId) }; memcpy(val.Memory, mem, GetTypeByteSize(val.TypeId)); env.Values[extract->ResultId] = val; break; } case Op::OpCompositeInsert: { auto insert = (SCompositeInsert*)op.Memory; auto composite = Dereference(env.Values[insert->CompositeId]); Value val = Dereference(env.Values.at(insert->ObjectId)); byte* mem = GetPointerInComposite(composite.TypeId, composite.Memory, insert->IndexesCount, insert->Indexes); memcpy(mem, val.Memory, GetTypeByteSize(val.TypeId)); env.Values[insert->ResultId] = VmInit(composite.TypeId, composite.Memory); break; } case Op::OpCompositeConstruct: { auto construct = (SCompositeConstruct*)op.Memory; Value val = { construct->ResultTypeId, VmAlloc(construct->ResultTypeId) }; env.Values[construct->ResultId] = val; byte* memPtr = val.Memory; for (int i = 0; i < construct->ConstituentsIdsCount; i++) { auto memVal = env.Values[construct->ConstituentsIds[i]]; uint32 memSize = GetTypeByteSize(memVal.TypeId); memcpy(memPtr, memVal.Memory, memSize); memPtr += memSize; } assert(memPtr - val.Memory == GetTypeByteSize(construct->ResultTypeId)); break; } case Op::OpVariable: { auto var = (SVariable*)op.Memory; Value val = { var->ResultTypeId, VmAlloc(var->ResultTypeId) }; if (var->InitializerId) { memcpy(val.Memory, env.Values[var->InitializerId].Memory, GetTypeByteSize(val.TypeId)); } else { memset(val.Memory, 0, GetTypeByteSize(val.TypeId)); } env.Values[var->ResultId] = val; break; } case Op::OpReturnValue: { auto ret = (SReturnValue*)op.Memory; return ret->ValueId; } case Op::OpReturn: return 0; default: std::cout << "Unimplemented operation: " << writeOp(op); return -1; } pc++; } return 0; }