@specs-feup/clava
Version:
A C/C++ source-to-source compiler written in Typescript
156 lines (128 loc) • 4.11 kB
text/typescript
import Query from "@specs-feup/lara/api/weaver/Query.js";
import { Call, FunctionJp } from "../../Joinpoints.js";
import MemoiUtils from "./MemoiUtils.js";
export default class MemoiTarget {
sig: string;
private $func: FunctionJp;
private isUser: boolean;
numInputs: number;
numOutputs: number;
inputTypes: string[];
outputTypes: string[];
private numCallSites: number;
constructor(
sig: string,
$func: FunctionJp,
isUser: boolean,
numInputs: number = $func.params.length,
numOuputs: number = 1,
inputTypes?: string[],
outputTypes?: string[],
numCallSites?: number
) {
this.sig = MemoiUtils.normalizeSig(sig);
this.$func = $func;
this.isUser = isUser;
this.numInputs = numInputs;
this.numOutputs = numOuputs;
if (inputTypes === undefined || outputTypes === undefined) {
[this.inputTypes, this.outputTypes] = this.findDataTypes();
} else {
this.inputTypes = inputTypes;
this.outputTypes = outputTypes;
}
this.numCallSites = numCallSites ?? this.findNumCallSites();
this.checkDataTypes();
}
static fromFunction($func: FunctionJp) {
const sig = MemoiUtils.normalizeSig($func.signature);
const isUser = !MemoiUtils.isWhiteListed(sig);
const numInputs = $func.params.length;
const numOutputs = 1;
// input types, output types, and num of call sites are found in the constructor
return new MemoiTarget(
sig,
$func,
isUser,
numInputs,
numOutputs,
undefined,
undefined
);
}
static fromCall($call: Call) {
const $func = $call.function;
if ($func === undefined) {
throw `Could not find function of call '${$call.code}'`;
}
return MemoiTarget.fromFunction($func);
}
static fromSig(sig: string) {
sig = MemoiUtils.normalizeSig(sig);
const $func = Query.search(FunctionJp, {
signature: (signature: string) =>
sig === MemoiUtils.normalizeSig(signature),
}).first();
if ($func === undefined) {
const $call = Query.search(Call, {
signature: (signature: string) =>
sig === MemoiUtils.normalizeSig(signature),
}).first();
if ($call === undefined) {
throw `Could not find function of sig '${sig}'`;
}
return MemoiTarget.fromCall($call);
}
return MemoiTarget.fromFunction($func);
}
private findNumCallSites(): number {
return Query.search(Call, {
signature: (signature: string) =>
this.sig === MemoiUtils.normalizeSig(signature),
}).get().length;
}
private findDataTypes() {
const inputTypes: string[] = [];
const outputTypes: string[] = [];
const $functionType = this.$func.functionType;
if (this.numOutputs == 1) {
outputTypes.push($functionType.returnType.code);
$functionType.paramTypes.forEach(function (e) {
inputTypes.push(e.code);
});
} else {
const typeCodes = $functionType.paramTypes.map(function (e) {
return e.code;
});
typeCodes.forEach((e, i) => {
if (i < this.numInputs) {
inputTypes.push(e);
} else {
outputTypes.push(e);
}
});
}
return [inputTypes, outputTypes];
}
private checkDataTypes() {
const normalTypes = ["double", "float", "int"];
const pointerTypes = ["double *", "float *", "int *"];
const inputsInvalid = this.inputTypes.some(function (e) {
return !normalTypes.includes(e);
});
if (inputsInvalid) {
throw `The inputs of the target function '${this.sig}' are not supported.`;
}
const outputTestArray = this.numOutputs == 1 ? normalTypes : pointerTypes;
const outputsInvalid = this.outputTypes.some(function (e) {
return !outputTestArray.includes(e);
});
if (outputsInvalid) {
throw `The outputs of the target function '${this.sig}' are not supported.`;
}
// if the output are valid, drop the pointer from the type
this.outputTypes = this.outputTypes.map(function (e) {
return e.replace(/\*/, "").trim();
});
}
}