1 /*
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/IR/Attributes.h>
22 #include <llvm/IR/DerivedTypes.h>
23 #include <llvm/IR/Function.h>
24 #include <llvm/IR/IRBuilder.h>
25 #include <llvm/IR/Intrinsics.h>
26
27 namespace art {
28 namespace llvm {
29
30 const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[] = {
31 #define DEF_INTRINSICS_FUNC(_, NAME, ATTR, RET_TYPE, ARG1_TYPE, ARG2_TYPE, \
32 ARG3_TYPE, ARG4_TYPE, \
33 ARG5_TYPE) \
34 { #NAME, ATTR, RET_TYPE, { ARG1_TYPE, ARG2_TYPE, \
35 ARG3_TYPE, ARG4_TYPE, \
36 ARG5_TYPE} },
37 #include "intrinsic_func_list.def"
38 };
39
GetLLVMTypeOfIntrinsicValType(IRBuilder & irb,IntrinsicHelper::IntrinsicValType type)40 static ::llvm::Type* GetLLVMTypeOfIntrinsicValType(IRBuilder& irb,
41 IntrinsicHelper::IntrinsicValType type) {
42 switch (type) {
43 case IntrinsicHelper::kVoidTy: {
44 return irb.getVoidTy();
45 }
46 case IntrinsicHelper::kJavaObjectTy: {
47 return irb.getJObjectTy();
48 }
49 case IntrinsicHelper::kJavaMethodTy: {
50 return irb.getJMethodTy();
51 }
52 case IntrinsicHelper::kJavaThreadTy: {
53 return irb.getJThreadTy();
54 }
55 case IntrinsicHelper::kInt1Ty:
56 case IntrinsicHelper::kInt1ConstantTy: {
57 return irb.getInt1Ty();
58 }
59 case IntrinsicHelper::kInt8Ty:
60 case IntrinsicHelper::kInt8ConstantTy: {
61 return irb.getInt8Ty();
62 }
63 case IntrinsicHelper::kInt16Ty:
64 case IntrinsicHelper::kInt16ConstantTy: {
65 return irb.getInt16Ty();
66 }
67 case IntrinsicHelper::kInt32Ty:
68 case IntrinsicHelper::kInt32ConstantTy: {
69 return irb.getInt32Ty();
70 }
71 case IntrinsicHelper::kInt64Ty:
72 case IntrinsicHelper::kInt64ConstantTy: {
73 return irb.getInt64Ty();
74 }
75 case IntrinsicHelper::kFloatTy:
76 case IntrinsicHelper::kFloatConstantTy: {
77 return irb.getFloatTy();
78 }
79 case IntrinsicHelper::kDoubleTy:
80 case IntrinsicHelper::kDoubleConstantTy: {
81 return irb.getDoubleTy();
82 }
83 case IntrinsicHelper::kNone:
84 case IntrinsicHelper::kVarArgTy:
85 default: {
86 LOG(FATAL) << "Invalid intrinsic type " << type << "to get LLVM type!";
87 return NULL;
88 }
89 }
90 // unreachable
91 }
92
IntrinsicHelper(::llvm::LLVMContext & context,::llvm::Module & module)93 IntrinsicHelper::IntrinsicHelper(::llvm::LLVMContext& context,
94 ::llvm::Module& module) {
95 IRBuilder irb(context, module, *this);
96
97 ::memset(intrinsic_funcs_, 0, sizeof(intrinsic_funcs_));
98
99 // This loop does the following things:
100 // 1. Introduce the intrinsic function into the module
101 // 2. Add "nocapture" and "noalias" attribute to the arguments in all
102 // intrinsics functions.
103 // 3. Initialize intrinsic_funcs_map_.
104 for (unsigned i = 0; i < MaxIntrinsicId; i++) {
105 IntrinsicId id = static_cast<IntrinsicId>(i);
106 const IntrinsicInfo& info = Info[i];
107
108 // Parse and construct the argument type from IntrinsicInfo
109 ::llvm::Type* arg_type[kIntrinsicMaxArgc];
110 unsigned num_args = 0;
111 bool is_var_arg = false;
112 for (unsigned arg_iter = 0; arg_iter < kIntrinsicMaxArgc; arg_iter++) {
113 IntrinsicValType type = info.arg_type_[arg_iter];
114
115 if (type == kNone) {
116 break;
117 } else if (type == kVarArgTy) {
118 // Variable argument type must be the last argument
119 is_var_arg = true;
120 break;
121 }
122
123 arg_type[num_args++] = GetLLVMTypeOfIntrinsicValType(irb, type);
124 }
125
126 // Construct the function type
127 ::llvm::Type* ret_type =
128 GetLLVMTypeOfIntrinsicValType(irb, info.ret_val_type_);
129
130 ::llvm::FunctionType* type =
131 ::llvm::FunctionType::get(ret_type,
132 ::llvm::ArrayRef< ::llvm::Type*>(arg_type, num_args),
133 is_var_arg);
134
135 // Declare the function
136 ::llvm::Function *fn = ::llvm::Function::Create(type,
137 ::llvm::Function::ExternalLinkage,
138 info.name_, &module);
139
140 if (info.attr_ & kAttrReadOnly) {
141 fn->setOnlyReadsMemory();
142 }
143 if (info.attr_ & kAttrReadNone) {
144 fn->setDoesNotAccessMemory();
145 }
146 // None of the intrinsics throws exception
147 fn->setDoesNotThrow();
148
149 intrinsic_funcs_[id] = fn;
150
151 DCHECK_NE(fn, static_cast< ::llvm::Function*>(NULL)) << "Intrinsic `"
152 << GetName(id) << "' was not defined!";
153
154 // Add "noalias" and "nocapture" attribute to all arguments of pointer type
155 for (::llvm::Function::arg_iterator arg_iter = fn->arg_begin(),
156 arg_end = fn->arg_end(); arg_iter != arg_end; arg_iter++) {
157 if (arg_iter->getType()->isPointerTy()) {
158 std::vector< ::llvm::Attribute::AttrKind> attributes;
159 attributes.push_back(::llvm::Attribute::NoCapture);
160 attributes.push_back(::llvm::Attribute::NoAlias);
161 ::llvm::AttributeSet attribute_set = ::llvm::AttributeSet::get(fn->getContext(),
162 arg_iter->getArgNo(),
163 attributes);
164 arg_iter->addAttr(attribute_set);
165 }
166 }
167
168 // Insert the newly created intrinsic to intrinsic_funcs_map_
169 if (!intrinsic_funcs_map_.insert(std::make_pair(fn, id)).second) {
170 LOG(FATAL) << "Duplicate entry in intrinsic functions map?";
171 }
172 }
173
174 return;
175 }
176
177 } // namespace llvm
178 } // namespace art
179