blob: b1837fb730942bb32b80e7bf69d6db93bf0a87ec [file] [log] [blame]
Shih-wei Liaoe94d9b22012-05-22 09:01:24 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "intrinsic_helper.h"
18
19#include "ir_builder.h"
20
21#include <llvm/DerivedTypes.h>
22#include <llvm/Function.h>
23#include <llvm/Intrinsics.h>
24#include <llvm/Module.h>
25#include <llvm/Support/IRBuilder.h>
26
27using namespace art;
28using namespace greenland;
29
30namespace {
31
32inline llvm::Type*
33GetLLVMTypeOfIntrinsicValType(IRBuilder& irb,
34 IntrinsicHelper::IntrinsicValType type) {
35 switch (type) {
36 case IntrinsicHelper::kVoidTy: {
37 return irb.getVoidTy();
38 }
39 case IntrinsicHelper::kJavaObjectTy: {
40 return irb.GetJObjectTy();
41 }
42 case IntrinsicHelper::kJavaMethodTy: {
43 return irb.GetJMethodTy();
44 }
45 case IntrinsicHelper::kJavaThreadTy: {
46 return irb.GetJThreadTy();
47 }
48 case IntrinsicHelper::kInt1Ty:
49 case IntrinsicHelper::kInt1ConstantTy: {
50 return irb.getInt1Ty();
51 }
52 case IntrinsicHelper::kInt8Ty:
53 case IntrinsicHelper::kInt8ConstantTy: {
54 return irb.getInt8Ty();
55 }
56 case IntrinsicHelper::kInt16Ty:
57 case IntrinsicHelper::kInt16ConstantTy: {
58 return irb.getInt16Ty();
59 }
60 case IntrinsicHelper::kInt32Ty:
61 case IntrinsicHelper::kInt32ConstantTy: {
62 return irb.getInt32Ty();
63 }
64 case IntrinsicHelper::kInt64Ty:
65 case IntrinsicHelper::kInt64ConstantTy: {
66 return irb.getInt64Ty();
67 }
buzbee2cfc6392012-05-07 14:51:40 -070068 case IntrinsicHelper::kFloatTy: {
69 return irb.getFloatTy();
70 }
71 case IntrinsicHelper::kDoubleTy: {
72 return irb.getDoubleTy();
73 }
Shih-wei Liaoe94d9b22012-05-22 09:01:24 -070074 case IntrinsicHelper::kNone:
75 case IntrinsicHelper::kVarArgTy:
76 default: {
77 LOG(FATAL) << "Invalid intrinsic type " << type << "to get LLVM type!";
78 return NULL;
79 }
80 }
81 // unreachable
82}
83
84} // anonymous namespace
85
86namespace art {
87namespace greenland {
88
89const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[MaxIntrinsicId] = {
90#define DEF_INTRINSICS_FUNC(_, NAME, ATTR, RET_TYPE, ARG1_TYPE, ARG2_TYPE, \
91 ARG3_TYPE, ARG4_TYPE, \
92 ARG5_TYPE) \
93 { #NAME, ATTR, RET_TYPE, { ARG1_TYPE, ARG2_TYPE, \
94 ARG3_TYPE, ARG4_TYPE, \
95 ARG5_TYPE} },
96#include "intrinsic_func_list.def"
97};
98
99IntrinsicHelper::IntrinsicHelper(llvm::LLVMContext& context,
100 llvm::Module& module) {
101 IRBuilder irb(context, module, *this);
102
103 ::memset(intrinsic_funcs_, 0, sizeof(intrinsic_funcs_));
104
105 // This loop does the following things:
106 // 1. Introduce the intrinsic function into the module
107 // 2. Add "nocapture" and "noalias" attribute to the arguments in all
108 // intrinsics functions.
109 // 3. Initialize intrinsic_funcs_map_.
110 for (unsigned i = 0; i < MaxIntrinsicId; i++) {
111 IntrinsicId id = static_cast<IntrinsicId>(i);
112 const IntrinsicInfo& info = Info[i];
113
114 // Parse and construct the argument type from IntrinsicInfo
115 llvm::Type* arg_type[kIntrinsicMaxArgc];
116 unsigned num_args = 0;
117 bool is_var_arg = false;
118 for (unsigned arg_iter = 0; arg_iter < kIntrinsicMaxArgc; arg_iter++) {
119 IntrinsicValType type = info.arg_type_[arg_iter];
120
121 if (type == kNone) {
122 break;
123 } else if (type == kVarArgTy) {
124 // Variable argument type must be the last argument
125 is_var_arg = true;
126 break;
127 }
128
129 arg_type[num_args++] = GetLLVMTypeOfIntrinsicValType(irb, type);
130 }
131
132 // Construct the function type
133 llvm::Type* ret_type =
134 GetLLVMTypeOfIntrinsicValType(irb, info.ret_val_type_);
135
136 llvm::FunctionType* type =
137 llvm::FunctionType::get(ret_type,
138 llvm::ArrayRef<llvm::Type*>(arg_type, num_args),
139 is_var_arg);
140
141 // Declare the function
142 llvm::Function *fn = llvm::Function::Create(type,
143 llvm::Function::ExternalLinkage,
144 info.name_, &module);
145
146 fn->setOnlyReadsMemory(info.attr_ & kAttrReadOnly);
147 // None of the intrinsics throws exception
148 fn->setDoesNotThrow(true);
149
150 intrinsic_funcs_[id] = fn;
151
152 DCHECK_NE(fn, static_cast<llvm::Function*>(NULL)) << "Intrinsic `"
153 << GetName(id) << "' was not defined!";
154
155 // Add "noalias" and "nocapture" attribute to all arguments of pointer type
156 for (llvm::Function::arg_iterator arg_iter = fn->arg_begin(),
157 arg_end = fn->arg_end(); arg_iter != arg_end; arg_iter++) {
158 if (arg_iter->getType()->isPointerTy()) {
159 arg_iter->addAttr(llvm::Attribute::NoCapture);
160 arg_iter->addAttr(llvm::Attribute::NoAlias);
161 }
162 }
163
164 // Insert the newly created intrinsic to intrinsic_funcs_map_
165 if (!intrinsic_funcs_map_.insert(std::make_pair(fn, id)).second) {
166 LOG(FATAL) << "Duplicate entry in intrinsic functions map?";
167 }
168 }
169
170 return;
171}
172
173} // namespace greenland
174} // namespace art